mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
+1
-1
@@ -7,7 +7,7 @@
|
||||
"dependencies": {
|
||||
"@capacitor/app": "1.1.1",
|
||||
"@floating-ui/react": "0.26.1",
|
||||
"@plebbit/plebbit-react-hooks": "https://github.com/plebbit/plebbit-react-hooks.git#00aabcce2276c671c0f4a371d459c93eb39c936a",
|
||||
"@plebbit/plebbit-react-hooks": "https://github.com/plebbit/plebbit-react-hooks.git#6d0d38ad52ce77715cb05be6cec55d691f5f013d",
|
||||
"@testing-library/jest-dom": "5.14.1",
|
||||
"@testing-library/react": "13.0.0",
|
||||
"@testing-library/user-event": "13.2.1",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 344 KiB |
+36
-27
@@ -1,20 +1,35 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Outlet, Route, Routes, useLocation } from 'react-router-dom';
|
||||
import { Outlet, Route, Routes, useLocation, useParams } from 'react-router-dom';
|
||||
import { isHomeView } from './lib/utils/view-utils';
|
||||
import useTheme from './hooks/use-theme';
|
||||
import styles from './app.module.css';
|
||||
import Board from './views/board';
|
||||
import Catalog from './views/catalog';
|
||||
import Home from './views/home';
|
||||
import PendingPost from './views/pending-post';
|
||||
import PostPage from './views/post-page';
|
||||
import Settings from './views/settings';
|
||||
import Board from './views/board';
|
||||
import BoardNav from './components/board-nav';
|
||||
import BoardBanner from './components/board-banner';
|
||||
import { DesktopBoardButtons } from './components/board-buttons';
|
||||
import { MobileBoardButtons } from './components/board-buttons';
|
||||
import { DesktopBoardButtons, MobileBoardButtons } from './components/board-buttons';
|
||||
import BoardNav from './components/board-nav';
|
||||
import ChallengeModal from './components/challenge-modal';
|
||||
import SubplebbitStats from './components/subplebbit-stats';
|
||||
import PostForm from './components/post-form';
|
||||
|
||||
const BoardLayout = () => {
|
||||
const { subplebbitAddress } = useParams();
|
||||
return (
|
||||
<>
|
||||
<BoardNav />
|
||||
<BoardBanner />
|
||||
<MobileBoardButtons />
|
||||
<PostForm key={subplebbitAddress} />
|
||||
<SubplebbitStats />
|
||||
<DesktopBoardButtons />
|
||||
<Outlet />
|
||||
</>
|
||||
);
|
||||
};
|
||||
const App = () => {
|
||||
const location = useLocation();
|
||||
const isInHomeView = isHomeView(location.pathname);
|
||||
@@ -26,21 +41,9 @@ const App = () => {
|
||||
document.body.classList.add(theme);
|
||||
}, [theme]);
|
||||
|
||||
// const globalLayout = (
|
||||
// <>
|
||||
// <ChallengeModal />
|
||||
// <Outlet />
|
||||
// </>
|
||||
// );
|
||||
|
||||
const boardLayout = (
|
||||
const globalLayout = (
|
||||
<>
|
||||
<BoardNav />
|
||||
<BoardBanner />
|
||||
<MobileBoardButtons />
|
||||
<PostForm />
|
||||
<SubplebbitStats />
|
||||
<DesktopBoardButtons />
|
||||
<ChallengeModal />
|
||||
<Outlet />
|
||||
</>
|
||||
);
|
||||
@@ -48,15 +51,21 @@ const App = () => {
|
||||
return (
|
||||
<div className={`${styles.app} ${isInHomeView ? 'yotsuba' : theme}`}>
|
||||
<Routes>
|
||||
<Route path='/' element={<Home />} />
|
||||
<Route element={boardLayout}>
|
||||
<Route path='/p/:subplebbitAddress' element={<Board />} />
|
||||
<Route path='/p/:subplebbitAddress/c/:commentCid' element={<PostPage />} />
|
||||
<Route path='/p/:subplebbitAddress/description' element={<PostPage />} />
|
||||
<Route path='/p/:subplebbitAddress/rules' element={<PostPage />} />
|
||||
<Route path='/p/:subplebbitAddress/catalog' element={<Catalog />} />
|
||||
<Route element={globalLayout}>
|
||||
<Route path='/' element={<Home />} />
|
||||
<Route element={<BoardLayout />}>
|
||||
<Route path='/p/:subplebbitAddress' element={<Board />} />
|
||||
|
||||
<Route path='/p/:subplebbitAddress/catalog' element={<Catalog />} />
|
||||
|
||||
<Route path='/p/:subplebbitAddress/c/:commentCid' element={<PostPage />} />
|
||||
<Route path='/p/:subplebbitAddress/description' element={<PostPage />} />
|
||||
<Route path='/p/:subplebbitAddress/rules' element={<PostPage />} />
|
||||
|
||||
<Route path='/profile/:accountCommentIndex' element={<PendingPost />} />
|
||||
</Route>
|
||||
<Route path='/settings' element={<Settings />} />
|
||||
</Route>
|
||||
<Route path='/settings' element={<Settings />} />
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { useAccountComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { useState } from 'react';
|
||||
import styles from './board-banner.module.css';
|
||||
|
||||
const totalBanners = 53;
|
||||
const totalBanners = 57;
|
||||
|
||||
const ImageBanner = () => {
|
||||
const [imagePath] = useState(() => {
|
||||
@@ -15,7 +15,10 @@ const ImageBanner = () => {
|
||||
};
|
||||
|
||||
const BoardBanner = () => {
|
||||
const { subplebbitAddress } = useParams<{ subplebbitAddress: string }>();
|
||||
const params = useParams();
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||
const { address, title } = subplebbit || {};
|
||||
const displayAddress = address && address.length > 10 && !address.includes('.') ? address.slice(0, 13).concat('...') : address;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import { useSubscribe } from '@plebbit/plebbit-react-hooks';
|
||||
import { useAccountComment, useSubscribe } from '@plebbit/plebbit-react-hooks';
|
||||
import styles from './board-buttons.module.css';
|
||||
import { isCatalogView, isPostPageView } from '../../lib/utils/view-utils';
|
||||
import { isCatalogView, isPendingPostView, isPostPageView } from '../../lib/utils/view-utils';
|
||||
|
||||
interface BoardButtonsProps {
|
||||
address: string | undefined;
|
||||
@@ -53,25 +53,30 @@ const BottomButton = () => {
|
||||
};
|
||||
|
||||
export const MobileBoardButtons = () => {
|
||||
const { subplebbitAddress: address } = useParams<{ subplebbitAddress: string }>();
|
||||
const isInPostPage = isPostPageView(useLocation().pathname, useParams());
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const isInPostPage = isPostPageView(location.pathname, params);
|
||||
const isInPendingPostPage = isPendingPostView(location.pathname, params);
|
||||
|
||||
return (
|
||||
<div className={styles.mobileBoardButtons}>
|
||||
{isInPostPage ? (
|
||||
{isInPostPage || isInPendingPostPage ? (
|
||||
<div className={styles.mobilePostPageButtons}>
|
||||
<ReturnButton address={address} />
|
||||
<CatalogButton address={address} />
|
||||
<ReturnButton address={subplebbitAddress} />
|
||||
<CatalogButton address={subplebbitAddress} />
|
||||
<BottomButton />
|
||||
<div className={styles.mobilePostPageButtonsSecondRow}>
|
||||
<OptionsButton />
|
||||
<SubscribeButton address={address} />
|
||||
<SubscribeButton address={subplebbitAddress} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<OptionsButton />
|
||||
<CatalogButton address={address} />
|
||||
<SubscribeButton address={address} />
|
||||
<CatalogButton address={subplebbitAddress} />
|
||||
<SubscribeButton address={subplebbitAddress} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -79,28 +84,30 @@ export const MobileBoardButtons = () => {
|
||||
};
|
||||
|
||||
export const DesktopBoardButtons = () => {
|
||||
const { subplebbitAddress: address } = useParams<{ subplebbitAddress: string }>();
|
||||
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const isInPostPage = isPostPageView(location.pathname, params);
|
||||
const isInCatalogView = isCatalogView(location.pathname, params);
|
||||
const isInPendingPostPage = isPendingPostView(location.pathname, params);
|
||||
|
||||
return (
|
||||
<div className={styles.desktopBoardButtons}>
|
||||
<hr />
|
||||
{isInPostPage ? (
|
||||
{isInPostPage || isInPendingPostPage ? (
|
||||
<>
|
||||
[<ReturnButton address={address} />] [<CatalogButton address={address} isInCatalogView={isInCatalogView} />] [<BottomButton />] [<OptionsButton />]
|
||||
[<ReturnButton address={subplebbitAddress} />] [<CatalogButton address={subplebbitAddress} isInCatalogView={isInCatalogView} />] [<BottomButton />] [
|
||||
<OptionsButton />]
|
||||
<span className={styles.subscribeButton}>
|
||||
[<SubscribeButton address={address} />]
|
||||
[<SubscribeButton address={subplebbitAddress} />]
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
[<OptionsButton />] [<CatalogButton address={address} isInCatalogView={isInCatalogView} />]
|
||||
[<OptionsButton />] [<CatalogButton address={subplebbitAddress} isInCatalogView={isInCatalogView} />]
|
||||
<span className={styles.subscribeButton}>
|
||||
[<SubscribeButton address={address} />]
|
||||
[<SubscribeButton address={subplebbitAddress} />]
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { isCatalogView } from '../../lib/utils/view-utils';
|
||||
@@ -22,7 +23,7 @@ const BoardNavDesktop = ({ subplebbitAddresses }: BoardNavProps) => {
|
||||
<span key={index}>
|
||||
{index === 0 ? null : ' '}
|
||||
<Link to={`/p/${address}${isInCatalogView ? '/catalog' : ''}`}>{address.includes('.') ? address : address.slice(0, 10).concat('...')}</Link>
|
||||
{index !== address.length - 1 ? ' /' : null}
|
||||
{index !== subplebbitAddresses.length - 1 ? ' /' : null}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
@@ -49,8 +50,7 @@ const BoardNavMobile = ({ subplebbitAddresses, subplebbitAddress }: BoardNavProp
|
||||
{!currentSubplebbitIsInList && subplebbitAddress && <option value={subplebbitAddress}>{displaySubplebbitAddress}</option>}
|
||||
<option value='all'>{t('all')}</option>
|
||||
<option value='subscriptions'>{t('subscriptions')}</option>
|
||||
{subplebbitAddresses.map((subplebbit: any, index: number) => {
|
||||
const address = subplebbit?.address || '';
|
||||
{subplebbitAddresses.map((address: any, index: number) => {
|
||||
const subplebbitAddress = address?.includes('.') ? address : address?.slice(0, 10).concat('...');
|
||||
return (
|
||||
<option key={index} value={address}>
|
||||
@@ -77,7 +77,11 @@ const BoardNavMobile = ({ subplebbitAddresses, subplebbitAddress }: BoardNavProp
|
||||
|
||||
const BoardNav = () => {
|
||||
const subplebbitAddresses = useDefaultSubplebbitAddresses();
|
||||
const { subplebbitAddress } = useParams();
|
||||
|
||||
const params = useParams();
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
|
||||
return (
|
||||
<>
|
||||
<BoardNavDesktop subplebbitAddresses={subplebbitAddresses} />
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
.postFormButtonDesktop {
|
||||
.postFormTable {
|
||||
width: auto;
|
||||
text-align: left;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: table;
|
||||
border-spacing: 1px;
|
||||
}
|
||||
|
||||
.postFormDesktop {
|
||||
font-size: var(--post-form-toggle-font-size);
|
||||
font-weight: var(--post-form-toggle-font-weight);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.postFormButtonMobile {
|
||||
.postFormMobile {
|
||||
text-align: center;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.postFormMobile .showFormButton {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.closed {
|
||||
font-size: x-large;
|
||||
text-align: center;
|
||||
@@ -19,14 +32,71 @@
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
.postFormTable td:first-child {
|
||||
background-color: var(--post-form-field-title-background-color);
|
||||
color: var(--post-form-field-title-color);
|
||||
font-weight: var(--post-form-field-title-font-weight);
|
||||
border: var(--post-form-field-border);
|
||||
padding: var(--post-form-field-title-padding);
|
||||
font-size: var(--post-form-field-title-font-size);
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.postFormTable td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 10pt;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.postFormTable input[type="text"], .postFormTable textarea {
|
||||
border: var(--post-form-field-input-border, revert);
|
||||
font-family: var(--post-form-field-font-family, revert);
|
||||
appearance: var(--post-form-field-input-appearance, revert);
|
||||
outline: var(--post-form-field-input-outline, revert);
|
||||
background-color: var(--post-form-field-input-background-color, revert);
|
||||
color: var(--post-form-field-input-color, revert);
|
||||
filter: var(--filter80);
|
||||
padding: 2px 4px 3px;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.postFormTable input[type="text"]:focus, .postFormTable textarea:focus {
|
||||
border: var(--post-form-field-input-focus-border, revert);
|
||||
}
|
||||
|
||||
.postFormTable td > input[type="text"] {
|
||||
width: 244px;
|
||||
}
|
||||
|
||||
.postFormTable textarea {
|
||||
width: 292px;
|
||||
|
||||
/* textareas have a gap below them that differs along browsers https://stackoverflow.com/a/7144960 */
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.postFormTable button {
|
||||
margin-left: 2px;
|
||||
filter: var(--filter80);
|
||||
}
|
||||
|
||||
.linkType {
|
||||
font-weight: normal;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
bottom: 3px;
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.postFormButtonDesktop {
|
||||
.postFormDesktop {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.postFormButtonMobile {
|
||||
.postFormMobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,63 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { useComment } from '@plebbit/plebbit-react-hooks';
|
||||
import { useAccount, useComment } from '@plebbit/plebbit-react-hooks';
|
||||
import { getLinkMediaInfo } from '../../lib/utils/media-utils';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isDescriptionView, isPostPageView, isRulesView } from '../../lib/utils/view-utils';
|
||||
import styles from './post-form.module.css';
|
||||
|
||||
const LinkTypePreviewer = ({ link }: { link: string }) => {
|
||||
const mediaInfo = getLinkMediaInfo(link);
|
||||
return isValidURL(link) ? mediaInfo?.type : 'Invalid URL';
|
||||
};
|
||||
|
||||
const PostFormTable = () => {
|
||||
const account = useAccount();
|
||||
const { displayName } = account || {};
|
||||
|
||||
const [link, setLink] = useState('');
|
||||
|
||||
return (
|
||||
<table className={styles.postFormTable}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>
|
||||
<input type='text' placeholder={!displayName ? 'Anonymous' : undefined} defaultValue={displayName || undefined} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Subject</td>
|
||||
<td>
|
||||
<input type='text' />
|
||||
<button>Post</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Comment</td>
|
||||
<td>
|
||||
<textarea cols={48} rows={4} wrap='soft' />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Link</td>
|
||||
<td>
|
||||
<input type='text' onChange={(e) => setLink(e.target.value)} />
|
||||
<span className={styles.linkType}>
|
||||
{link && (
|
||||
<>
|
||||
(<LinkTypePreviewer link={link} />)
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
const PostForm = () => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
@@ -23,14 +76,14 @@ const PostForm = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.postFormButtonDesktop}>
|
||||
<div className={styles.postFormDesktop}>
|
||||
{isThreadClosed ? (
|
||||
<div className={styles.closed}>
|
||||
{t('thread_closed')}
|
||||
<br />
|
||||
{t('may_not_reply')}
|
||||
</div>
|
||||
) : (
|
||||
) : !showForm ? (
|
||||
<div>
|
||||
[
|
||||
<button className='button' onClick={() => setShowForm(true)}>
|
||||
@@ -38,9 +91,11 @@ const PostForm = () => {
|
||||
</button>
|
||||
]
|
||||
</div>
|
||||
) : (
|
||||
<PostFormTable />
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.postFormButtonMobile}>
|
||||
<div className={styles.postFormMobile}>
|
||||
{isThreadClosed ? (
|
||||
<div className={styles.closed}>
|
||||
{t('thread_closed')}
|
||||
@@ -48,9 +103,12 @@ const PostForm = () => {
|
||||
{t('may_not_reply')}
|
||||
</div>
|
||||
) : (
|
||||
<button className='button' onClick={() => setShowForm(true)}>
|
||||
{isInPostPage ? t('post_a_reply') : t('start_new_thread')}
|
||||
</button>
|
||||
<>
|
||||
<button className={`${styles.showFormButton} button`} onClick={() => setShowForm(showForm ? false : true)}>
|
||||
{showForm ? t('close_post_form') : isInPostPage ? t('post_a_reply') : t('start_new_thread')}
|
||||
</button>
|
||||
{showForm && <PostFormTable />}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -312,6 +312,7 @@
|
||||
clear: both;
|
||||
background-color: var(--post-mobile-link-background-color);
|
||||
border-top: var(--post-mobile-link-border-top);
|
||||
border-bottom: var(--post-mobile-link-border-bottom);
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
@@ -37,6 +37,7 @@ const PostDesktop = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
|
||||
const commentMediaInfo = getCommentMediaInfo(post);
|
||||
const { type, url } = commentMediaInfo || {};
|
||||
const embedUrl = url && new URL(url);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
const [showThumbnail, setShowThumbnail] = useState(true);
|
||||
|
||||
@@ -76,7 +77,7 @@ const PostDesktop = ({ post, roles, showAllReplies }: PostProps) => {
|
||||
]
|
||||
</span>
|
||||
)}
|
||||
{showThumbnail && !hasThumbnail && (
|
||||
{showThumbnail && !hasThumbnail && embedUrl && canEmbed(embedUrl) && (
|
||||
<span>
|
||||
{' '}
|
||||
[
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
import { useState } from 'react';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { useComment, useSubplebbit, useSubplebbitStats } from '@plebbit/plebbit-react-hooks';
|
||||
import { useAccountComment, useComment, useSubplebbit, useSubplebbitStats } from '@plebbit/plebbit-react-hooks';
|
||||
import styles from './subplebbit-stats.module.css';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { isDescriptionView, isRulesView } from '../../lib/utils/view-utils';
|
||||
|
||||
const SubplebbitStats = () => {
|
||||
const { t } = useTranslation();
|
||||
const { commentCid, subplebbitAddress } = useParams<{ subplebbitAddress: string; commentCid: string }>();
|
||||
const params = useParams();
|
||||
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||
const { address, createdAt } = subplebbit || {};
|
||||
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const isInDescriptionView = isDescriptionView(location.pathname, params);
|
||||
const isInRulesView = isRulesView(location.pathname, params);
|
||||
|
||||
const comment = useComment({ commentCid });
|
||||
const comment = useComment({ commentCid: params?.commentCid });
|
||||
const { deleted, locked, removed } = comment || {};
|
||||
const hideStats = deleted || locked || removed || isInDescriptionView || isInRulesView;
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@ const useRepliesAndAccountReplies = (comment: Comment) => {
|
||||
}, [flattenedReplies, accountComments]);
|
||||
|
||||
const repliesAndNotYetPublishedReplies = useMemo(() => {
|
||||
return [
|
||||
const repliesSortedByVotes = [
|
||||
// put the author's unpublished replies at the top, latest first (reverse)
|
||||
...accountRepliesNotYetPublished.reverse(),
|
||||
// put the published replies after,
|
||||
...(flattenedReplies || []),
|
||||
];
|
||||
// sort by timestamp
|
||||
return repliesSortedByVotes.sort((a: Comment, b: Comment) => a.timestamp - b.timestamp);
|
||||
}, [flattenedReplies, accountRepliesNotYetPublished]);
|
||||
|
||||
return repliesAndNotYetPublishedReplies;
|
||||
|
||||
@@ -45,7 +45,7 @@ const getPatternThumbnailUrl = (url: URL): string | undefined => {
|
||||
}
|
||||
};
|
||||
|
||||
const getLinkMediaInfo = memoize(
|
||||
export const getLinkMediaInfo = memoize(
|
||||
(link: string): CommentMediaInfo | undefined => {
|
||||
if (!isValidURL(link)) {
|
||||
return;
|
||||
@@ -56,7 +56,8 @@ const getLinkMediaInfo = memoize(
|
||||
let mime: string | undefined;
|
||||
|
||||
try {
|
||||
mime = extName(url.pathname.slice(url.pathname.lastIndexOf('/') + 1))[0]?.mime;
|
||||
const fileName = url.pathname.slice(url.pathname.lastIndexOf('/') + 1).toLowerCase();
|
||||
mime = extName(fileName)[0]?.mime;
|
||||
if (mime) {
|
||||
if (mime.startsWith('image')) {
|
||||
type = mime === 'image/gif' ? 'gif' : 'image';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export type ParamsType = {
|
||||
accountCommentIndex?: string;
|
||||
commentCid?: string;
|
||||
subplebbitAddress?: string;
|
||||
};
|
||||
@@ -29,3 +30,7 @@ export const isCatalogView = (pathname: string, params: ParamsType): boolean =>
|
||||
const decodedPathname = decodeURIComponent(pathname);
|
||||
return params.subplebbitAddress ? decodedPathname.startsWith(`/p/${params.subplebbitAddress}/catalog`) : false;
|
||||
};
|
||||
|
||||
export const isPendingPostView = (pathname: string, params: ParamsType): boolean => {
|
||||
return pathname === `/profile/${params.accountCommentIndex}`;
|
||||
};
|
||||
|
||||
+58
-2
@@ -112,6 +112,17 @@
|
||||
/* 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;
|
||||
|
||||
/* quotelink */
|
||||
--post-quotelink-text-color: navy;
|
||||
@@ -242,6 +253,17 @@
|
||||
/* post form */
|
||||
--post-form-toggle-font-size: 22px;
|
||||
--post-form-toggle-font-weight: 700;
|
||||
--post-form-field-title-background-color: #98e;
|
||||
--post-form-field-title-color: #000;
|
||||
--post-form-field-border: 1px solid #000;
|
||||
--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 #98e;
|
||||
|
||||
/* quotelink */
|
||||
--post-quotelink-text-color: #d00;
|
||||
@@ -349,6 +371,11 @@
|
||||
/* 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: none;
|
||||
--post-form-field-title-font-weight: 700;
|
||||
--post-form-field-title-font-size: 16px;
|
||||
|
||||
/* quotelink */
|
||||
--post-quotelink-text-color: navy;
|
||||
@@ -470,6 +497,11 @@
|
||||
/* post form */
|
||||
--post-form-toggle-font-size: 22px;
|
||||
--post-form-toggle-font-weight: 700;
|
||||
--post-form-field-title-background-color: #98e;
|
||||
--post-form-field-title-color: #000;
|
||||
--post-form-field-border: none;
|
||||
--post-form-field-title-font-weight: 700;
|
||||
--post-form-field-title-font-size: 16px;
|
||||
|
||||
/* quotelink */
|
||||
--post-quotelink-text-color: #d00;
|
||||
@@ -572,6 +604,7 @@
|
||||
|
||||
/* post mobile */
|
||||
--post-mobile-background-color: #282A2E;
|
||||
--post-mobile-info-border-top: 1px solid #2D2F33;
|
||||
--post-mobile-info-border-bottom: 1px solid #2D2F33;
|
||||
--post-mobile-info-background-color: #212326;
|
||||
--post-mobile-info-text-color: #707070;
|
||||
@@ -582,6 +615,7 @@
|
||||
--post-mobile-subject-font-weight: 700;
|
||||
--post-mobile-link-background-color: #212326;
|
||||
--post-mobile-link-border-top: 1px solid #2D2F33;
|
||||
--post-mobile-link-border-bottom: 1px solid #2D2F33;
|
||||
--post-mobile-link-info-text-color: #707070;
|
||||
--post-mobile-abbr-text-color: #707070;
|
||||
--post-mobile-abbr-font-size: 10pt;
|
||||
@@ -604,6 +638,17 @@
|
||||
/* post form */
|
||||
--post-form-toggle-font-size: 22px;
|
||||
--post-form-toggle-font-weight: 700;
|
||||
--post-form-field-title-background-color: #282a2e;
|
||||
--post-form-field-title-color: #c5c8c6;
|
||||
--post-form-field-border: 1px solid #111;
|
||||
--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 #111;
|
||||
|
||||
/* select */
|
||||
--select-border: 1px solid #575a60;
|
||||
@@ -687,8 +732,8 @@
|
||||
|
||||
/* post mobile */
|
||||
--post-mobile-background-color: #eee;
|
||||
--post-mobile-info-border-bottom: 1px solid #ccc;
|
||||
--post-mobile-info-border-top: 1px solid #ccc;
|
||||
--post-mobile-info-border-bottom: 1px solid #ccc;
|
||||
--post-mobile-info-background-color: #ddd;
|
||||
--post-mobile-info-text-color: #707070;
|
||||
--post-mobile-menu-button-color: #f60;
|
||||
@@ -698,11 +743,11 @@
|
||||
--post-mobile-subject-font-weight: 700;
|
||||
--post-mobile-link-background-color: #ddd;
|
||||
--post-mobile-link-border-top: 1px solid #ccc;
|
||||
--post-mobile-link-border-bottom: 1px solid #ccc;
|
||||
--post-mobile-link-info-text-color: #333;
|
||||
--post-mobile-abbr-text-color: #333;
|
||||
--post-mobile-abbr-font-size: 10pt;
|
||||
--post-mobile-content-font-size: 11pt;
|
||||
--post-mobile-border-bottom: 1px solid #ccc;
|
||||
|
||||
/* post capcodes */
|
||||
--post-capcode-mod-text-color: #f60;
|
||||
@@ -710,6 +755,17 @@
|
||||
/* post form */
|
||||
--post-form-toggle-font-size: 22px;
|
||||
--post-form-toggle-font-weight: 700;
|
||||
--post-form-field-title-background-color: #ddd;
|
||||
--post-form-field-title-color: #333;
|
||||
--post-form-field-border: 1px solid #ccc;
|
||||
--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;
|
||||
|
||||
/* quotelink */
|
||||
--post-quotelink-text-color: #f60;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './pending-post';
|
||||
@@ -0,0 +1,16 @@
|
||||
.stateString {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: calc(100vw - 28px);
|
||||
width: 100vw;
|
||||
margin-top: 10px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.stateString {
|
||||
margin-top: 0px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||
import styles from './pending-post.module.css';
|
||||
import Post from '../../components/post';
|
||||
import useStateString from '../../hooks/use-state-string';
|
||||
import LoadingEllipsis from '../../components/loading-ellipsis';
|
||||
|
||||
const PendingPost = () => {
|
||||
const { accountCommentIndex } = useParams<{ accountCommentIndex?: string }>();
|
||||
const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined;
|
||||
const post = useAccountComment({ commentIndex });
|
||||
const navigate = useNavigate();
|
||||
const stateString = useStateString(post);
|
||||
|
||||
useEffect(() => window.scrollTo(0, 0), []);
|
||||
|
||||
useEffect(() => {
|
||||
if (post?.cid && post?.subplebbitAddress) {
|
||||
navigate(`/p/${post?.subplebbitAddress}/c/${post?.cid}`, { replace: true });
|
||||
}
|
||||
}, [post, navigate]);
|
||||
|
||||
const loadingString = stateString && (
|
||||
<div className={`${styles.stateString} ${styles.ellipsis}`}>{stateString !== 'Failed' ? <LoadingEllipsis string={stateString} /> : stateString}</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Post post={post} />
|
||||
{loadingString}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PendingPost;
|
||||
@@ -3409,6 +3409,68 @@
|
||||
uuid "9.0.1"
|
||||
viem "1.5.2"
|
||||
|
||||
"@plebbit/plebbit-js@https://github.com/plebbit/plebbit-js.git#347579798478c27eea4808b923ab6f21799fce89":
|
||||
version "0.0.3"
|
||||
resolved "https://github.com/plebbit/plebbit-js.git#347579798478c27eea4808b923ab6f21799fce89"
|
||||
dependencies:
|
||||
"@bonfida/spl-name-service" "2.3.8"
|
||||
"@chainsafe/libp2p-gossipsub" "12.0.0"
|
||||
"@chainsafe/libp2p-noise" "15.0.0"
|
||||
"@chainsafe/libp2p-yamux" "6.0.2"
|
||||
"@ensdomains/eth-ens-namehash" "2.0.15"
|
||||
"@keyv/sqlite" "3.6.7"
|
||||
"@libp2p/autonat" "1.0.12"
|
||||
"@libp2p/bootstrap" "10.0.15"
|
||||
"@libp2p/circuit-relay-v2" "^1.0.15"
|
||||
"@libp2p/identify" "1.0.14"
|
||||
"@libp2p/kad-dht" "12.0.7"
|
||||
"@libp2p/mplex" "10.0.15"
|
||||
"@libp2p/peer-id-factory" "4.0.6"
|
||||
"@libp2p/webrtc" "4.0.19"
|
||||
"@libp2p/webtransport" "4.0.19"
|
||||
"@plebbit/plebbit-logger" "github:plebbit/plebbit-logger#355a96d7659ed820047980049dfa627d30d83a69"
|
||||
"@plebbit/proper-lockfile" "github:plebbit/node-proper-lockfile#7fd6332117340c1d3d98dd0afee2d31cc06f72b8"
|
||||
"@types/proper-lockfile" "4.1.2"
|
||||
"@types/uuid" "8.3.4"
|
||||
assert "2.1.0"
|
||||
better-sqlite3 "9.3.0"
|
||||
buffer "6.0.3"
|
||||
captcha-canvas "3.2.1"
|
||||
cbor "9.0.1"
|
||||
debounce "1.2.1"
|
||||
err-code "3.0.1"
|
||||
ethers "6.10.0"
|
||||
ext-name "5.0.0"
|
||||
file-type "16.5.4"
|
||||
hpagent "1.2.0"
|
||||
ipfs-only-hash "4.0.0"
|
||||
jose "4.11.0"
|
||||
js-sha256 "0.9.0"
|
||||
keyv "4.5.4"
|
||||
knex "3.1.0"
|
||||
kubo-rpc-client "3.0.3"
|
||||
libp2p "1.2.1"
|
||||
libp2p-crypto "0.21.2"
|
||||
limiter-es6-compat "2.1.2"
|
||||
localforage "1.10.0"
|
||||
lodash-es "4.17.21"
|
||||
lru-cache "10.1.0"
|
||||
open-graph-scraper "6.3.3"
|
||||
p-limit "4.0.0"
|
||||
p-timeout "6.1.2"
|
||||
peer-id "0.16.0"
|
||||
probe-image-size "7.2.3"
|
||||
retry "0.13.1"
|
||||
rpc-websockets "7.9.0"
|
||||
safe-stable-stringify "2.4.3"
|
||||
sha1-uint8array "0.10.7"
|
||||
skia-canvas "1.0.0"
|
||||
tiny-typed-emitter "2.1.0"
|
||||
tinycache "1.1.2"
|
||||
ts-custom-error "3.3.1"
|
||||
uuid "9.0.1"
|
||||
viem "1.5.2"
|
||||
|
||||
"@plebbit/plebbit-logger@github:plebbit/plebbit-logger#355a96d7659ed820047980049dfa627d30d83a69":
|
||||
version "0.0.1"
|
||||
uid "355a96d7659ed820047980049dfa627d30d83a69"
|
||||
@@ -3438,6 +3500,22 @@
|
||||
uuid "8.3.2"
|
||||
zustand "4.0.0"
|
||||
|
||||
"@plebbit/plebbit-react-hooks@https://github.com/plebbit/plebbit-react-hooks.git#6d0d38ad52ce77715cb05be6cec55d691f5f013d":
|
||||
version "0.0.1"
|
||||
resolved "https://github.com/plebbit/plebbit-react-hooks.git#6d0d38ad52ce77715cb05be6cec55d691f5f013d"
|
||||
dependencies:
|
||||
"@plebbit/plebbit-js" "https://github.com/plebbit/plebbit-js.git#347579798478c27eea4808b923ab6f21799fce89"
|
||||
"@plebbit/plebbit-logger" "https://github.com/plebbit/plebbit-logger.git"
|
||||
assert "2.0.0"
|
||||
ethers "5.6.9"
|
||||
localforage "1.10.0"
|
||||
lodash.isequal "4.5.0"
|
||||
memoizee "0.4.15"
|
||||
quick-lru "5.1.1"
|
||||
uint8arrays "3.1.1"
|
||||
uuid "8.3.2"
|
||||
zustand "4.0.0"
|
||||
|
||||
"@plebbit/proper-lockfile@github:plebbit/node-proper-lockfile#7fd6332117340c1d3d98dd0afee2d31cc06f72b8":
|
||||
version "4.1.2"
|
||||
resolved "https://codeload.github.com/plebbit/node-proper-lockfile/tar.gz/7fd6332117340c1d3d98dd0afee2d31cc06f72b8"
|
||||
|
||||
Reference in New Issue
Block a user