mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
refactor: rebrand default subplebbits to 5chan directories
This commit is contained in:
@@ -23,7 +23,7 @@ Currently, directory assignments are temporarily handpicked by developers throug
|
|||||||
|
|
||||||
### How It Works
|
### How It Works
|
||||||
|
|
||||||
- **Current System**: Developers manually curate directory assignments by reviewing pull requests to the [5chan-multisub.json](https://github.com/bitsocialhq/lists/blob/master/5chan-multisub.json) file.
|
- **Current System**: Developers manually curate directory assignments by reviewing pull requests to the [5chan-directories.json](https://github.com/bitsocialhq/lists/blob/master/5chan-directories.json) file.
|
||||||
|
|
||||||
- **Future System**: Directory board assignments will be determined through gasless voting using pubsub. Community members will vote on which board should be assigned to each directory, and the highest-voted board will automatically become the directory board. This creates a competitive marketplace where board quality and community engagement determine directory placement.
|
- **Future System**: Directory board assignments will be determined through gasless voting using pubsub. Community members will vote on which board should be assigned to each directory, and the highest-voted board will automatically become the directory board. This creates a competitive marketplace where board quality and community engagement determine directory placement.
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ To have your board appear in a directory on the 5chan homepage:
|
|||||||
- Relevant to the directory category
|
- Relevant to the directory category
|
||||||
- **99% uptime** (since a board acts like its own server—it's a P2P node)
|
- **99% uptime** (since a board acts like its own server—it's a P2P node)
|
||||||
|
|
||||||
2. Open a pull request on GitHub by editing the [5chan-multisub.json](https://github.com/bitsocialhq/lists/blob/master/5chan-multisub.json) file
|
2. Open a pull request on GitHub by editing the [5chan-directories.json](https://github.com/bitsocialhq/lists/blob/master/5chan-directories.json) file
|
||||||
|
|
||||||
3. Add your board's entry with:
|
3. Add your board's entry with:
|
||||||
- Title: in the format `/directoryCode/ - Title`, e.g. "/biz/ - Business & Finance";
|
- Title: in the format `/directoryCode/ - Title`, e.g. "/biz/ - Business & Finance";
|
||||||
|
|||||||
+3
-3
@@ -9,7 +9,7 @@ import useCreateBoardModalStore from './stores/use-create-board-modal-store';
|
|||||||
import useSpecialThemeStore from './stores/use-special-theme-store';
|
import useSpecialThemeStore from './stores/use-special-theme-store';
|
||||||
import useIsMobile from './hooks/use-is-mobile';
|
import useIsMobile from './hooks/use-is-mobile';
|
||||||
import useTheme from './hooks/use-theme';
|
import useTheme from './hooks/use-theme';
|
||||||
import { useDefaultSubplebbits } from './hooks/use-default-subplebbits';
|
import { useDirectories } from './hooks/use-directories';
|
||||||
import { getSubplebbitAddress, isPostRoute, isPendingPostRoute, isModQueueRoute } from './lib/utils/route-utils';
|
import { getSubplebbitAddress, isPostRoute, isPendingPostRoute, isModQueueRoute } from './lib/utils/route-utils';
|
||||||
import styles from './app.module.css';
|
import styles from './app.module.css';
|
||||||
import FAQ from './views/faq';
|
import FAQ from './views/faq';
|
||||||
@@ -44,8 +44,8 @@ const BoardLayout = () => {
|
|||||||
const isInAllView = isAllView(location.pathname);
|
const isInAllView = isAllView(location.pathname);
|
||||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||||
const isInModView = isModView(location.pathname);
|
const isInModView = isModView(location.pathname);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const subplebbitAddress = boardIdentifier ? getSubplebbitAddress(boardIdentifier, defaultSubplebbits) : undefined;
|
const subplebbitAddress = boardIdentifier ? getSubplebbitAddress(boardIdentifier, directories) : undefined;
|
||||||
const pendingPost = useAccountComment({ commentIndex: accountCommentIndex ? parseInt(accountCommentIndex) : undefined });
|
const pendingPost = useAccountComment({ commentIndex: accountCommentIndex ? parseInt(accountCommentIndex) : undefined });
|
||||||
const { closeCreateBoardModal } = useCreateBoardModalStore();
|
const { closeCreateBoardModal } = useCreateBoardModalStore();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
|||||||
import { useAccountComment, useSubscribe } from '@plebbit/plebbit-react-hooks';
|
import { useAccountComment, useSubscribe } from '@plebbit/plebbit-react-hooks';
|
||||||
import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages';
|
import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages';
|
||||||
import { isAllView, isCatalogView, isModView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isCatalogView, isModView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { getBoardPath, isDirectoryBoard } from '../../lib/utils/route-utils';
|
import { getBoardPath, isDirectoryBoard } from '../../lib/utils/route-utils';
|
||||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||||
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
||||||
@@ -35,7 +35,7 @@ interface BoardButtonsProps {
|
|||||||
const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModView }: BoardButtonsProps) => {
|
const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModView }: BoardButtonsProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const createCatalogLink = () => {
|
const createCatalogLink = () => {
|
||||||
if (isInAllView) {
|
if (isInAllView) {
|
||||||
@@ -50,9 +50,9 @@ const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModVie
|
|||||||
}
|
}
|
||||||
let boardPath = '';
|
let boardPath = '';
|
||||||
if (address) {
|
if (address) {
|
||||||
boardPath = getBoardPath(address, defaultSubplebbits);
|
boardPath = getBoardPath(address, directories);
|
||||||
} else if (Array.isArray(defaultSubplebbits) && defaultSubplebbits.length > 0 && defaultSubplebbits[0]?.address) {
|
} else if (Array.isArray(directories) && directories.length > 0 && directories[0]?.address) {
|
||||||
boardPath = getBoardPath(defaultSubplebbits[0].address, defaultSubplebbits);
|
boardPath = getBoardPath(directories[0].address, directories);
|
||||||
}
|
}
|
||||||
return `/${boardPath}/catalog`;
|
return `/${boardPath}/catalog`;
|
||||||
};
|
};
|
||||||
@@ -78,7 +78,7 @@ const SubscribeButton = ({ address }: BoardButtonsProps) => {
|
|||||||
const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView, isInModQueueView }: BoardButtonsProps) => {
|
const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView, isInModQueueView }: BoardButtonsProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const createReturnLink = () => {
|
const createReturnLink = () => {
|
||||||
if (isInAllView) {
|
if (isInAllView) {
|
||||||
@@ -99,9 +99,9 @@ const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView
|
|||||||
}
|
}
|
||||||
let boardPath = '';
|
let boardPath = '';
|
||||||
if (address) {
|
if (address) {
|
||||||
boardPath = getBoardPath(address, defaultSubplebbits);
|
boardPath = getBoardPath(address, directories);
|
||||||
} else if (Array.isArray(defaultSubplebbits) && defaultSubplebbits.length > 0 && defaultSubplebbits[0]?.address) {
|
} else if (Array.isArray(directories) && directories.length > 0 && directories[0]?.address) {
|
||||||
boardPath = getBoardPath(defaultSubplebbits[0].address, defaultSubplebbits);
|
boardPath = getBoardPath(directories[0].address, directories);
|
||||||
}
|
}
|
||||||
return `/${boardPath}`;
|
return `/${boardPath}`;
|
||||||
};
|
};
|
||||||
@@ -116,13 +116,13 @@ const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView
|
|||||||
const VoteButton = () => {
|
const VoteButton = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
// Get the boardIdentifier from params (try boardIdentifier first, then subplebbitAddress for backward compatibility)
|
// Get the boardIdentifier from params (try boardIdentifier first, then subplebbitAddress for backward compatibility)
|
||||||
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
||||||
|
|
||||||
// Only render the vote button if we're on a directory board route
|
// Only render the vote button if we're on a directory board route
|
||||||
if (!boardIdentifier || !isDirectoryBoard(boardIdentifier, defaultSubplebbits)) {
|
if (!boardIdentifier || !isDirectoryBoard(boardIdentifier, directories)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,9 +418,9 @@ export const MobileBoardButtons = () => {
|
|||||||
const { filteredCount, searchText } = useCatalogFiltersStore();
|
const { filteredCount, searchText } = useCatalogFiltersStore();
|
||||||
|
|
||||||
// Check if we should show the vote button (only for directory boards)
|
// Check if we should show the vote button (only for directory boards)
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
||||||
const showVoteButton = boardIdentifier && isDirectoryBoard(boardIdentifier, defaultSubplebbits);
|
const showVoteButton = boardIdentifier && isDirectoryBoard(boardIdentifier, directories);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.mobileBoardButtons} ${!isInCatalogView ? styles.addMargin : ''}`}>
|
<div className={`${styles.mobileBoardButtons} ${!isInCatalogView ? styles.addMargin : ''}`}>
|
||||||
@@ -539,9 +539,9 @@ export const DesktopBoardButtons = () => {
|
|||||||
const { filteredCount, searchText } = useCatalogFiltersStore();
|
const { filteredCount, searchText } = useCatalogFiltersStore();
|
||||||
|
|
||||||
// Check if we should show the vote button (only for directory boards)
|
// Check if we should show the vote button (only for directory boards)
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
||||||
const showVoteButton = boardIdentifier && isDirectoryBoard(boardIdentifier, defaultSubplebbits);
|
const showVoteButton = boardIdentifier && isDirectoryBoard(boardIdentifier, directories);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -655,9 +655,9 @@ const SearchOPsBar = () => {
|
|||||||
const isInAllView = isAllView(location.pathname);
|
const isInAllView = isAllView(location.pathname);
|
||||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||||
const isInModView = isModView(location.pathname);
|
const isInModView = isModView(location.pathname);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||||
const boardPath = resolvedAddress ? getBoardPath(resolvedAddress, defaultSubplebbits) : params?.boardIdentifier || params?.subplebbitAddress;
|
const boardPath = resolvedAddress ? getBoardPath(resolvedAddress, directories) : params?.boardIdentifier || params?.subplebbitAddress;
|
||||||
|
|
||||||
const handleSearch = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleSearch = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import Plebbit from '@plebbit/plebbit-js';
|
|||||||
import { useStableSubplebbit } from '../../hooks/use-stable-subplebbit';
|
import { useStableSubplebbit } from '../../hooks/use-stable-subplebbit';
|
||||||
import { isAllView, isSubscriptionsView, isModView } from '../../lib/utils/view-utils';
|
import { isAllView, isSubscriptionsView, isModView } from '../../lib/utils/view-utils';
|
||||||
import styles from './board-header.module.css';
|
import styles from './board-header.module.css';
|
||||||
import { useMultisubMetadata, useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectoriesMetadata, useDirectories } from '../../hooks/use-directories';
|
||||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||||
import useIsMobile from '../../hooks/use-is-mobile';
|
import useIsMobile from '../../hooks/use-is-mobile';
|
||||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||||
@@ -59,11 +59,11 @@ const BoardHeader = () => {
|
|||||||
const stableSubplebbit = useStableSubplebbit(subplebbitAddress);
|
const stableSubplebbit = useStableSubplebbit(subplebbitAddress);
|
||||||
const { address, shortAddress } = stableSubplebbit || {};
|
const { address, shortAddress } = stableSubplebbit || {};
|
||||||
|
|
||||||
const multisubMetadata = useMultisubMetadata();
|
const directoriesMetadata = useDirectoriesMetadata();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
// Find matching subplebbit from default list to get its title
|
// Find matching subplebbit from default list to get its title
|
||||||
const defaultSubplebbit = subplebbitAddress ? defaultSubplebbits.find((s) => s.address === subplebbitAddress) : null;
|
const defaultSubplebbit = subplebbitAddress ? directories.find((s) => s.address === subplebbitAddress) : null;
|
||||||
|
|
||||||
// Use accounts store with selector to only subscribe to subscriptions count
|
// Use accounts store with selector to only subscribe to subscriptions count
|
||||||
const subscriptionsCount = useAccountsStore((state) => {
|
const subscriptionsCount = useAccountsStore((state) => {
|
||||||
@@ -74,7 +74,7 @@ const BoardHeader = () => {
|
|||||||
const subscriptionsSubtitle = t('subscriptions_subtitle', { count: subscriptionsCount });
|
const subscriptionsSubtitle = t('subscriptions_subtitle', { count: subscriptionsCount });
|
||||||
|
|
||||||
const title = isInAllView
|
const title = isInAllView
|
||||||
? multisubMetadata?.title || '/all/ - 5chan Directories'
|
? directoriesMetadata?.title || '/all/ - 5chan Directories'
|
||||||
: isInSubscriptionsView
|
: isInSubscriptionsView
|
||||||
? '/subs/ - Subscriptions'
|
? '/subs/ - Subscriptions'
|
||||||
: isInModView
|
: isInModView
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { shouldShowSnow } from '../../lib/snow';
|
|||||||
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
||||||
import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||||
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||||
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
||||||
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
|
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
|
||||||
@@ -125,8 +125,8 @@ const CatalogPost = memo(
|
|||||||
const params = useParams();
|
const params = useParams();
|
||||||
const isInAllView = isAllView(location.pathname);
|
const isInAllView = isAllView(location.pathname);
|
||||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : '';
|
||||||
const postMenuProps = useMemo(() => selectPostMenuProps(post), [post]);
|
const postMenuProps = useMemo(() => selectPostMenuProps(post), [post]);
|
||||||
|
|
||||||
const postLink = boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`;
|
const postLink = boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`;
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ const CreateBoardModal = () => {
|
|||||||
<h3>Submitting to a Directory</h3>
|
<h3>Submitting to a Directory</h3>
|
||||||
<p>
|
<p>
|
||||||
Open a PR editing{' '}
|
Open a PR editing{' '}
|
||||||
<a href='https://github.com/plebbit/lists/blob/master/5chan-multisub.json' target='_blank' rel='noopener noreferrer'>
|
<a href='https://github.com/plebbit/lists/blob/master/5chan-directories.json' target='_blank' rel='noopener noreferrer'>
|
||||||
5chan-multisub.json
|
5chan-directories.json
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
with your board's title, address, and NSFW status. Devs will review and merge if approved. 99% uptime is required.
|
with your board's title, address, and NSFW status. Devs will review and merge if approved. 99% uptime is required.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ const DirectoryModal = () => {
|
|||||||
<h3>Directory Submission</h3>
|
<h3>Directory Submission</h3>
|
||||||
<p>
|
<p>
|
||||||
To submit your board, open a PR editing{' '}
|
To submit your board, open a PR editing{' '}
|
||||||
<a href='https://github.com/plebbit/lists/blob/master/5chan-multisub.json' target='_blank' rel='noopener noreferrer'>
|
<a href='https://github.com/plebbit/lists/blob/master/5chan-directories.json' target='_blank' rel='noopener noreferrer'>
|
||||||
5chan-multisub.json
|
5chan-directories.json
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
with your board's title, address, and NSFW status. Requirements: 99% uptime (they're P2P nodes), active, well-moderated, and relevant to the
|
with your board's title, address, and NSFW status. Requirements: 99% uptime (they're P2P nodes), active, well-moderated, and relevant to the
|
||||||
category. Devs will review and approve/reject based on these criteria.
|
category. Devs will review and approve/reject based on these criteria.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-util
|
|||||||
import { isValidURL } from '../../lib/utils/url-utils';
|
import { isValidURL } from '../../lib/utils/url-utils';
|
||||||
import { isAllView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import useModQueueStore from '../../stores/use-mod-queue-store';
|
import useModQueueStore from '../../stores/use-mod-queue-store';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||||
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
|
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
|
||||||
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
||||||
@@ -85,8 +85,8 @@ const PostInfo = ({
|
|||||||
const { showOmittedReplies } = useShowOmittedReplies();
|
const { showOmittedReplies } = useShowOmittedReplies();
|
||||||
const { imageUrl: avatarImageUrl } = useAuthorAvatar({ author });
|
const { imageUrl: avatarImageUrl } = useAuthorAvatar({ author });
|
||||||
const { hideAvatars } = useAvatarVisibilityStore();
|
const { hideAvatars } = useAvatarVisibilityStore();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : undefined;
|
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : undefined;
|
||||||
const postMenuProps = useMemo(() => selectPostMenuProps(post), [post]);
|
const postMenuProps = useMemo(() => selectPostMenuProps(post), [post]);
|
||||||
|
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
@@ -453,7 +453,7 @@ const PostMedia = ({
|
|||||||
const { url } = commentMediaInfo || {};
|
const { url } = commentMediaInfo || {};
|
||||||
let type = commentMediaInfo?.type;
|
let type = commentMediaInfo?.type;
|
||||||
const gifFrameUrl = useFetchGifFirstFrame(url);
|
const gifFrameUrl = useFetchGifFirstFrame(url);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
if (type === 'gif' && gifFrameUrl !== null) {
|
if (type === 'gif' && gifFrameUrl !== null) {
|
||||||
type = 'animated gif';
|
type = 'animated gif';
|
||||||
@@ -465,7 +465,7 @@ const PostMedia = ({
|
|||||||
const [showThumbnail, setShowThumbnail] = useState(true);
|
const [showThumbnail, setShowThumbnail] = useState(true);
|
||||||
|
|
||||||
const mediaDimensions = getMediaDimensions(commentMediaInfo);
|
const mediaDimensions = getMediaDimensions(commentMediaInfo);
|
||||||
const boardPath = getBoardPath(subplebbitAddress, defaultSubplebbits);
|
const boardPath = getBoardPath(subplebbitAddress, directories);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.file}>
|
<div className={styles.file}>
|
||||||
@@ -528,8 +528,8 @@ const Reply = ({ postReplyCount, reply, roles, threadNumber }: PostProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { author, cid, deleted, link, linkHeight, linkWidth, postCid, reason, removed, spoiler, subplebbitAddress, thumbnailUrl, parentCid } = post || {};
|
const { author, cid, deleted, link, linkHeight, linkWidth, postCid, reason, removed, spoiler, subplebbitAddress, thumbnailUrl, parentCid } = post || {};
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : undefined;
|
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : undefined;
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const route = boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`;
|
const route = boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`;
|
||||||
@@ -591,8 +591,8 @@ const PostDesktop = ({
|
|||||||
const isInPostPageView = isPostPageView(location.pathname, params);
|
const isInPostPageView = isPostPageView(location.pathname, params);
|
||||||
const isInAllView = isAllView(location.pathname);
|
const isInAllView = isAllView(location.pathname);
|
||||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : undefined;
|
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : undefined;
|
||||||
|
|
||||||
const { hidden, unhide, hide } = useHide({ cid });
|
const { hidden, unhide, hide } = useHide({ cid });
|
||||||
const isHidden = hidden && !isInPostPageView;
|
const isHidden = hidden && !isInPostPageView;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { getCommentMediaInfo } from '../../../lib/utils/media-utils';
|
|||||||
import { copyShareLinkToClipboard, isValidURL, type ShareLinkType } from '../../../lib/utils/url-utils';
|
import { copyShareLinkToClipboard, isValidURL, type ShareLinkType } from '../../../lib/utils/url-utils';
|
||||||
import { copyToClipboard } from '../../../lib/utils/clipboard-utils';
|
import { copyToClipboard } from '../../../lib/utils/clipboard-utils';
|
||||||
import { getBoardPath } from '../../../lib/utils/route-utils';
|
import { getBoardPath } from '../../../lib/utils/route-utils';
|
||||||
import { useDefaultSubplebbits } from '../../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../../hooks/use-directories';
|
||||||
import { isAllView, isCatalogView, isPostPageView, isSubscriptionsView } from '../../../lib/utils/view-utils';
|
import { isAllView, isCatalogView, isPostPageView, isSubscriptionsView } from '../../../lib/utils/view-utils';
|
||||||
import useHide from '../../../hooks/use-hide';
|
import useHide from '../../../hooks/use-hide';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -21,8 +21,8 @@ type CopyLinkButtonProps =
|
|||||||
|
|
||||||
const CopyLinkButton = ({ cid, subplebbitAddress, linkType, onClose }: CopyLinkButtonProps) => {
|
const CopyLinkButton = ({ cid, subplebbitAddress, linkType, onClose }: CopyLinkButtonProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardIdentifier = getBoardPath(subplebbitAddress, defaultSubplebbits);
|
const boardIdentifier = getBoardPath(subplebbitAddress, directories);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { getHasThumbnail, getLinkMediaInfo } from '../../lib/utils/media-utils';
|
|||||||
import { formatMarkdown } from '../../lib/utils/post-utils';
|
import { formatMarkdown } from '../../lib/utils/post-utils';
|
||||||
import { isValidURL } from '../../lib/utils/url-utils';
|
import { isValidURL } from '../../lib/utils/url-utils';
|
||||||
import { isAllView, isCatalogView, isModQueueView, isModView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isCatalogView, isModQueueView, isModView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||||
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
||||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||||
@@ -71,7 +71,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
const isInModView = isModView(location.pathname);
|
const isInModView = isModView(location.pathname);
|
||||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||||
const subscriptions = account?.subscriptions || [];
|
const subscriptions = account?.subscriptions || [];
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const { accountSubplebbits } = useAccountSubplebbits();
|
const { accountSubplebbits } = useAccountSubplebbits();
|
||||||
const accountSubplebbitAddresses = Object.keys(accountSubplebbits);
|
const accountSubplebbitAddresses = Object.keys(accountSubplebbits);
|
||||||
@@ -338,7 +338,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
<select onChange={(e) => setPublishPostOptions({ subplebbitAddress: e.target.value })} value={subplebbitAddress}>
|
<select onChange={(e) => setPublishPostOptions({ subplebbitAddress: e.target.value })} value={subplebbitAddress}>
|
||||||
<option value=''>{t('choose_one')}</option>
|
<option value=''>{t('choose_one')}</option>
|
||||||
{isInAllView &&
|
{isInAllView &&
|
||||||
defaultSubplebbits
|
directories
|
||||||
.filter((subplebbit) => subplebbit.title && subplebbit.address)
|
.filter((subplebbit) => subplebbit.title && subplebbit.address)
|
||||||
.map((subplebbit) => (
|
.map((subplebbit) => (
|
||||||
<option key={subplebbit.address} value={subplebbit.address}>
|
<option key={subplebbit.address} value={subplebbit.address}>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { getCommentMediaInfo } from '../../../lib/utils/media-utils';
|
|||||||
import { copyShareLinkToClipboard, isValidURL, type ShareLinkType } from '../../../lib/utils/url-utils';
|
import { copyShareLinkToClipboard, isValidURL, type ShareLinkType } from '../../../lib/utils/url-utils';
|
||||||
import { copyToClipboard } from '../../../lib/utils/clipboard-utils';
|
import { copyToClipboard } from '../../../lib/utils/clipboard-utils';
|
||||||
import { getBoardPath } from '../../../lib/utils/route-utils';
|
import { getBoardPath } from '../../../lib/utils/route-utils';
|
||||||
import { useDefaultSubplebbits } from '../../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../../hooks/use-directories';
|
||||||
import useEditCommentPrivileges from '../../../hooks/use-author-privileges';
|
import useEditCommentPrivileges from '../../../hooks/use-author-privileges';
|
||||||
import useHide from '../../../hooks/use-hide';
|
import useHide from '../../../hooks/use-hide';
|
||||||
import EditMenu from '../../edit-menu/edit-menu';
|
import EditMenu from '../../edit-menu/edit-menu';
|
||||||
@@ -29,8 +29,8 @@ type CopyLinkButtonProps =
|
|||||||
|
|
||||||
const CopyLinkButton = ({ cid, subplebbitAddress, linkType, onClose }: CopyLinkButtonProps) => {
|
const CopyLinkButton = ({ cid, subplebbitAddress, linkType, onClose }: CopyLinkButtonProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardIdentifier = getBoardPath(subplebbitAddress, defaultSubplebbits);
|
const boardIdentifier = getBoardPath(subplebbitAddress, directories);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/po
|
|||||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||||
import { isAllView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import useModQueueStore from '../../stores/use-mod-queue-store';
|
import useModQueueStore from '../../stores/use-mod-queue-store';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||||
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
|
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
|
||||||
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
||||||
@@ -40,10 +40,10 @@ const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
|
|||||||
|
|
||||||
const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: PostProps) => {
|
const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: PostProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const { author, cid, deleted, link, linkHeight, linkWidth, locked, parentCid, pinned, postCid, reason, removed, state, subplebbitAddress, timestamp, thumbnailUrl } =
|
const { author, cid, deleted, link, linkHeight, linkWidth, locked, parentCid, pinned, postCid, reason, removed, state, subplebbitAddress, timestamp, thumbnailUrl } =
|
||||||
post || {};
|
post || {};
|
||||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : undefined;
|
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : undefined;
|
||||||
const isReply = parentCid;
|
const isReply = parentCid;
|
||||||
const title = post?.title?.trim();
|
const title = post?.title?.trim();
|
||||||
const { address, shortAddress } = author || {};
|
const { address, shortAddress } = author || {};
|
||||||
@@ -397,8 +397,8 @@ const Reply = ({ postReplyCount, reply, roles, threadNumber }: PostProps) => {
|
|||||||
post = editedComment;
|
post = editedComment;
|
||||||
}
|
}
|
||||||
const { author, cid, deleted, postCid, reason, removed, subplebbitAddress } = post || {};
|
const { author, cid, deleted, postCid, reason, removed, subplebbitAddress } = post || {};
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : undefined;
|
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : undefined;
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const route = boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`;
|
const route = boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`;
|
||||||
const isRouteLinkToReply = cid ? location.pathname.startsWith(route) : false;
|
const isRouteLinkToReply = cid ? location.pathname.startsWith(route) : false;
|
||||||
@@ -442,8 +442,8 @@ const PostMobile = ({
|
|||||||
const navigationType = useNavigationType();
|
const navigationType = useNavigationType();
|
||||||
const isInPendingPostView = isPendingPostView(location.pathname, params);
|
const isInPendingPostView = isPendingPostView(location.pathname, params);
|
||||||
const isInPostView = isPostPageView(location.pathname, params);
|
const isInPostView = isPostPageView(location.pathname, params);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : undefined;
|
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : undefined;
|
||||||
const linksCount = useCountLinksInReplies(post);
|
const linksCount = useCountLinksInReplies(post);
|
||||||
const { replies, hasMore, loadMore } = useReplies({ comment: post, accountComments: { newerThan: Infinity } });
|
const { replies, hasMore, loadMore } = useReplies({ comment: post, accountComments: { newerThan: Infinity } });
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { createPortal } from 'react-dom';
|
|||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { Comment, useAccount } from '@plebbit/plebbit-react-hooks';
|
import { Comment, useAccount } from '@plebbit/plebbit-react-hooks';
|
||||||
import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react';
|
import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||||
import useIsMobile from '../../hooks/use-is-mobile';
|
import useIsMobile from '../../hooks/use-is-mobile';
|
||||||
import styles from '../../views/post/post.module.css';
|
import styles from '../../views/post/post.module.css';
|
||||||
@@ -59,7 +59,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
|||||||
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
||||||
const placementRef = useRef<Placement>('right');
|
const placementRef = useRef<Placement>('right');
|
||||||
const availableWidthRef = useRef<number>(0);
|
const availableWidthRef = useRef<number>(0);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const { refs, floatingStyles, update } = useFloating({
|
const { refs, floatingStyles, update } = useFloating({
|
||||||
placement: placementRef.current,
|
placement: placementRef.current,
|
||||||
@@ -102,7 +102,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
|||||||
const handleClick = (e: React.MouseEvent, cid: string | undefined, subplebbitAddress: string | undefined) => {
|
const handleClick = (e: React.MouseEvent, cid: string | undefined, subplebbitAddress: string | undefined) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (cid && subplebbitAddress) {
|
if (cid && subplebbitAddress) {
|
||||||
const boardPath = getBoardPath(subplebbitAddress, defaultSubplebbits);
|
const boardPath = getBoardPath(subplebbitAddress, directories);
|
||||||
navigate(`/${boardPath}/thread/${cid}`);
|
navigate(`/${boardPath}/thread/${cid}`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const element = document.querySelector(`[data-cid="${cid}"]`);
|
const element = document.querySelector(`[data-cid="${cid}"]`);
|
||||||
@@ -130,7 +130,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
|||||||
setOutOfViewCid(null);
|
setOutOfViewCid(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const backlinkBoardPath = backlinkReply?.subplebbitAddress ? getBoardPath(backlinkReply.subplebbitAddress, defaultSubplebbits) : undefined;
|
const backlinkBoardPath = backlinkReply?.subplebbitAddress ? getBoardPath(backlinkReply.subplebbitAddress, directories) : undefined;
|
||||||
const backlinkRoute = backlinkReply?.cid ? (backlinkBoardPath ? `/${backlinkBoardPath}/thread/${backlinkReply.cid}` : `/thread/${backlinkReply.cid}`) : '#';
|
const backlinkRoute = backlinkReply?.cid ? (backlinkBoardPath ? `/${backlinkBoardPath}/thread/${backlinkReply.cid}` : `/thread/${backlinkReply.cid}`) : '#';
|
||||||
|
|
||||||
const replyBacklink = (
|
const replyBacklink = (
|
||||||
@@ -159,7 +159,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
|||||||
|
|
||||||
const account = useAccount();
|
const account = useAccount();
|
||||||
|
|
||||||
const quotelinkBoardPath = quotelinkReply?.subplebbitAddress ? getBoardPath(quotelinkReply.subplebbitAddress, defaultSubplebbits) : undefined;
|
const quotelinkBoardPath = quotelinkReply?.subplebbitAddress ? getBoardPath(quotelinkReply.subplebbitAddress, directories) : undefined;
|
||||||
const quotelinkRoute = quotelinkReply?.cid ? (quotelinkBoardPath ? `/${quotelinkBoardPath}/thread/${quotelinkReply.cid}` : `/thread/${quotelinkReply.cid}`) : '#';
|
const quotelinkRoute = quotelinkReply?.cid ? (quotelinkBoardPath ? `/${quotelinkBoardPath}/thread/${quotelinkReply.cid}` : `/thread/${quotelinkReply.cid}`) : '#';
|
||||||
|
|
||||||
const replyQuotelink = (
|
const replyQuotelink = (
|
||||||
@@ -193,7 +193,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
|||||||
const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
|
const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
|
||||||
const [hoveredCid, setHoveredCid] = useState<string | null>(null);
|
const [hoveredCid, setHoveredCid] = useState<string | null>(null);
|
||||||
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const { refs, floatingStyles, update } = useFloating({
|
const { refs, floatingStyles, update } = useFloating({
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
@@ -215,7 +215,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
|||||||
const handleClick = (e: React.MouseEvent, cid: string | undefined, subplebbitAddress: string | undefined) => {
|
const handleClick = (e: React.MouseEvent, cid: string | undefined, subplebbitAddress: string | undefined) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (cid && subplebbitAddress) {
|
if (cid && subplebbitAddress) {
|
||||||
const boardPath = getBoardPath(subplebbitAddress, defaultSubplebbits);
|
const boardPath = getBoardPath(subplebbitAddress, directories);
|
||||||
navigate(`/${boardPath}/thread/${cid}`);
|
navigate(`/${boardPath}/thread/${cid}`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const element = document.querySelector(`[data-cid="${cid}"]`);
|
const element = document.querySelector(`[data-cid="${cid}"]`);
|
||||||
@@ -255,7 +255,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
|||||||
</span>
|
</span>
|
||||||
{backlinkReply?.number &&
|
{backlinkReply?.number &&
|
||||||
(() => {
|
(() => {
|
||||||
const backlinkBoardPath = backlinkReply?.subplebbitAddress ? getBoardPath(backlinkReply.subplebbitAddress, defaultSubplebbits) : undefined;
|
const backlinkBoardPath = backlinkReply?.subplebbitAddress ? getBoardPath(backlinkReply.subplebbitAddress, directories) : undefined;
|
||||||
const backlinkRoute = backlinkReply?.cid ? (backlinkBoardPath ? `/${backlinkBoardPath}/thread/${backlinkReply.cid}` : `/thread/${backlinkReply.cid}`) : '#';
|
const backlinkRoute = backlinkReply?.cid ? (backlinkBoardPath ? `/${backlinkBoardPath}/thread/${backlinkReply.cid}` : `/thread/${backlinkReply.cid}`) : '#';
|
||||||
return (
|
return (
|
||||||
<Link to={backlinkRoute} className={styles.backlinkHash} onClick={(e) => handleClick(e, backlinkReply?.cid, backlinkReply?.subplebbitAddress)}>
|
<Link to={backlinkRoute} className={styles.backlinkHash} onClick={(e) => handleClick(e, backlinkReply?.cid, backlinkReply?.subplebbitAddress)}>
|
||||||
@@ -290,7 +290,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
|||||||
</span>
|
</span>
|
||||||
{quotelinkReply?.number &&
|
{quotelinkReply?.number &&
|
||||||
(() => {
|
(() => {
|
||||||
const quotelinkBoardPath = quotelinkReply?.subplebbitAddress ? getBoardPath(quotelinkReply.subplebbitAddress, defaultSubplebbits) : undefined;
|
const quotelinkBoardPath = quotelinkReply?.subplebbitAddress ? getBoardPath(quotelinkReply.subplebbitAddress, directories) : undefined;
|
||||||
const quotelinkRoute = quotelinkReply?.cid
|
const quotelinkRoute = quotelinkReply?.cid
|
||||||
? quotelinkBoardPath
|
? quotelinkBoardPath
|
||||||
? `/${quotelinkBoardPath}/thread/${quotelinkReply.cid}`
|
? `/${quotelinkBoardPath}/thread/${quotelinkReply.cid}`
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Plebbit from '@plebbit/plebbit-js';
|
|||||||
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||||
import useAccountsStore from '@plebbit/plebbit-react-hooks/dist/stores/accounts';
|
import useAccountsStore from '@plebbit/plebbit-react-hooks/dist/stores/accounts';
|
||||||
import { isAllView, isCatalogView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isCatalogView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import { useDefaultSubplebbits, MultisubSubplebbit } from '../../hooks/use-default-subplebbits';
|
import { useDirectories, DirectoryCommunity } from '../../hooks/use-directories';
|
||||||
import { useBoardPath, useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
import { useBoardPath, useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||||
import { getBoardPath, extractDirectoryFromTitle } from '../../lib/utils/route-utils';
|
import { getBoardPath, extractDirectoryFromTitle } from '../../lib/utils/route-utils';
|
||||||
import { TimeFilter } from '../board-buttons';
|
import { TimeFilter } from '../board-buttons';
|
||||||
@@ -77,8 +77,8 @@ const SearchBar = ({ setShowSearchBar }: { setShowSearchBar: (show: boolean) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to find board address by directory code
|
// Helper function to find board address by directory code
|
||||||
const findBoardAddressByCode = (code: string, defaultSubplebbits: MultisubSubplebbit[]): string | null => {
|
const findBoardAddressByCode = (code: string, directories: DirectoryCommunity[]): string | null => {
|
||||||
const entry = defaultSubplebbits.find((subplebbit) => {
|
const entry = directories.find((subplebbit) => {
|
||||||
if (!subplebbit.title) return false;
|
if (!subplebbit.title) return false;
|
||||||
const directory = extractDirectoryFromTitle(subplebbit.title);
|
const directory = extractDirectoryFromTitle(subplebbit.title);
|
||||||
return directory === code;
|
return directory === code;
|
||||||
@@ -97,7 +97,7 @@ const TopBarDesktop = () => {
|
|||||||
const { openTopbarEditModal } = useTopbarEditModalStore();
|
const { openTopbarEditModal } = useTopbarEditModalStore();
|
||||||
const { openDirectoryModal } = useDirectoryModalStore();
|
const { openDirectoryModal } = useDirectoryModalStore();
|
||||||
const { visibleDirectories, visibleSubscriptions } = useTopbarVisibilityStore();
|
const { visibleDirectories, visibleSubscriptions } = useTopbarVisibilityStore();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
// Memoize allBoardCodes since it's derived from a constant
|
// Memoize allBoardCodes since it's derived from a constant
|
||||||
const allBoardCodes = useMemo(() => getAllBoardCodes(), []);
|
const allBoardCodes = useMemo(() => getAllBoardCodes(), []);
|
||||||
@@ -150,7 +150,7 @@ const TopBarDesktop = () => {
|
|||||||
|
|
||||||
// Render a board code link or placeholder
|
// Render a board code link or placeholder
|
||||||
const renderBoardCode = (code: string, isLastInGroup: boolean) => {
|
const renderBoardCode = (code: string, isLastInGroup: boolean) => {
|
||||||
const address = findBoardAddressByCode(code, defaultSubplebbits);
|
const address = findBoardAddressByCode(code, directories);
|
||||||
const isPlaceholder = !address;
|
const isPlaceholder = !address;
|
||||||
|
|
||||||
const handleClick = (e: React.MouseEvent) => {
|
const handleClick = (e: React.MouseEvent) => {
|
||||||
@@ -186,7 +186,7 @@ const TopBarDesktop = () => {
|
|||||||
|
|
||||||
// Render a subscription link
|
// Render a subscription link
|
||||||
const renderSubscription = (address: string, index: number, total: number) => {
|
const renderSubscription = (address: string, index: number, total: number) => {
|
||||||
const boardPath = getBoardPath(address, defaultSubplebbits);
|
const boardPath = getBoardPath(address, directories);
|
||||||
const displayText = address.endsWith('.eth') || address.endsWith('.sol') ? address : Plebbit.getShortAddress({ address });
|
const displayText = address.endsWith('.eth') || address.endsWith('.sol') ? address : Plebbit.getShortAddress({ address });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -249,12 +249,12 @@ const TopBarDesktop = () => {
|
|||||||
const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => {
|
const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const displaySubplebbitAddress = subplebbitAddress && subplebbitAddress.length > 30 ? subplebbitAddress.slice(0, 30).concat('...') : subplebbitAddress;
|
const displaySubplebbitAddress = subplebbitAddress && subplebbitAddress.length > 30 ? subplebbitAddress.slice(0, 30).concat('...') : subplebbitAddress;
|
||||||
const [showSearchBar, setShowSearchBar] = useState(false);
|
const [showSearchBar, setShowSearchBar] = useState(false);
|
||||||
|
|
||||||
// Filter to only show directory boards (those with titles)
|
// Filter to only show directory boards (those with titles)
|
||||||
const directoryBoards = useMemo(() => defaultSubplebbits.filter((sub) => sub.title && extractDirectoryFromTitle(sub.title)), [defaultSubplebbits]);
|
const directoryBoards = useMemo(() => directories.filter((sub) => sub.title && extractDirectoryFromTitle(sub.title)), [directories]);
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "Each 5chan directory is assigned to a board (subplebbit) handpicked by the team, until DAO curation is implemented.\n\nhttps://github.com/plebbit/temporary-default-subplebbits",
|
"description": "Each 5chan directory is assigned to a board (subplebbit) handpicked by the team, until DAO curation is implemented.\n\nhttps://github.com/plebbit/temporary-default-subplebbits",
|
||||||
"createdAt": 1762179811,
|
"createdAt": 1762179811,
|
||||||
"updatedAt": 1762179811,
|
"updatedAt": 1762179811,
|
||||||
"subplebbits": [
|
"communities": [
|
||||||
{
|
{
|
||||||
"title": "/pol/ - Politically Incorrect",
|
"title": "/pol/ - Politically Incorrect",
|
||||||
"address": "politically-incorrect.eth",
|
"address": "politically-incorrect.eth",
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import useAccountsStore from '@plebbit/plebbit-react-hooks/dist/stores/accounts';
|
import useAccountsStore from '@plebbit/plebbit-react-hooks/dist/stores/accounts';
|
||||||
import { MultisubSubplebbit } from './use-default-subplebbits';
|
import { DirectoryCommunity } from './use-directories';
|
||||||
|
|
||||||
export const useAccountSubplebbitsWithMetadata = (): MultisubSubplebbit[] => {
|
export const useAccountSubplebbitsWithMetadata = (): DirectoryCommunity[] => {
|
||||||
const subplebbitsWithMetadata = useAccountsStore(
|
const subplebbitsWithMetadata = useAccountsStore(
|
||||||
(state) => {
|
(state) => {
|
||||||
const activeAccountId = state.activeAccountId;
|
const activeAccountId = state.activeAccountId;
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import defaultSubplebbitsData from '../data/default-subplebbits.json';
|
import directoriesData from '../data/5chan-directories.json';
|
||||||
|
|
||||||
export interface MultisubMetadata {
|
export interface DirectoriesMetadata {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MultisubSubplebbit {
|
export interface DirectoryCommunity {
|
||||||
title?: string;
|
title?: string;
|
||||||
address: string;
|
address: string;
|
||||||
nsfw?: boolean;
|
nsfw?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MultisubData {
|
export interface DirectoriesData {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
subplebbits: MultisubSubplebbit[];
|
communities: DirectoryCommunity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DefaultSubplebbitsState {
|
export interface DirectoriesState {
|
||||||
subplebbits: MultisubSubplebbit[];
|
communities: DirectoryCommunity[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: Error | null;
|
error: Error | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GITHUB_URL = 'https://raw.githubusercontent.com/plebbit/lists/master/5chan-multisub.json';
|
const GITHUB_URL = 'https://raw.githubusercontent.com/plebbit/lists/master/5chan-directories.json';
|
||||||
const LOCALSTORAGE_KEY = '5chan-subplebbits-cache';
|
const LOCALSTORAGE_KEY = '5chan-directories-cache';
|
||||||
const LOCALSTORAGE_TIMESTAMP_KEY = '5chan-subplebbits-cache-timestamp';
|
const LOCALSTORAGE_TIMESTAMP_KEY = '5chan-directories-cache-timestamp';
|
||||||
const CACHE_MAX_AGE_MS = 60 * 60 * 1000; // 1 hour
|
const CACHE_MAX_AGE_MS = 60 * 60 * 1000; // 1 hour
|
||||||
|
|
||||||
let cacheSubplebbits: MultisubSubplebbit[] | null = null;
|
let cacheCommunities: DirectoryCommunity[] | null = null;
|
||||||
let cacheMetadata: MultisubMetadata | null = null;
|
let cacheMetadata: DirectoriesMetadata | null = null;
|
||||||
|
|
||||||
const getFromLocalStorage = (): MultisubData | null => {
|
const getFromLocalStorage = (): DirectoriesData | null => {
|
||||||
try {
|
try {
|
||||||
const cached = localStorage.getItem(LOCALSTORAGE_KEY);
|
const cached = localStorage.getItem(LOCALSTORAGE_KEY);
|
||||||
const timestamp = localStorage.getItem(LOCALSTORAGE_TIMESTAMP_KEY);
|
const timestamp = localStorage.getItem(LOCALSTORAGE_TIMESTAMP_KEY);
|
||||||
@@ -52,7 +52,7 @@ const getFromLocalStorage = (): MultisubData | null => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveToLocalStorage = (data: MultisubData) => {
|
const saveToLocalStorage = (data: DirectoriesData) => {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(data));
|
localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(data));
|
||||||
localStorage.setItem(LOCALSTORAGE_TIMESTAMP_KEY, Date.now().toString());
|
localStorage.setItem(LOCALSTORAGE_TIMESTAMP_KEY, Date.now().toString());
|
||||||
@@ -61,7 +61,7 @@ const saveToLocalStorage = (data: MultisubData) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchMultisubData = async (): Promise<MultisubData> => {
|
const fetchDirectoriesData = async (): Promise<DirectoriesData> => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(GITHUB_URL);
|
const response = await fetch(GITHUB_URL);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -72,25 +72,25 @@ const fetchMultisubData = async (): Promise<MultisubData> => {
|
|||||||
saveToLocalStorage(data);
|
saveToLocalStorage(data);
|
||||||
return data;
|
return data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to fetch subplebbits from GitHub, using vendored fallback:', e);
|
console.warn('Failed to fetch directories from GitHub, using vendored fallback:', e);
|
||||||
// Fall back to vendored file
|
// Fall back to vendored file
|
||||||
return defaultSubplebbitsData as MultisubData;
|
return directoriesData as DirectoriesData;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDefaultSubplebbits = () => {
|
export const useDirectories = () => {
|
||||||
// Use vendored data as initial state to prevent theme flash on first load
|
// Use vendored data as initial state to prevent theme flash on first load
|
||||||
// This ensures NSFW status is known synchronously before first render
|
// This ensures NSFW status is known synchronously before first render
|
||||||
const [state, setState] = useState<DefaultSubplebbitsState>({
|
const [state, setState] = useState<DirectoriesState>({
|
||||||
subplebbits: (defaultSubplebbitsData as MultisubData).subplebbits,
|
communities: (directoriesData as DirectoriesData).communities,
|
||||||
loading: true,
|
loading: true,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cacheSubplebbits) {
|
if (cacheCommunities) {
|
||||||
setState({
|
setState({
|
||||||
subplebbits: cacheSubplebbits,
|
communities: cacheCommunities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
@@ -104,21 +104,21 @@ export const useDefaultSubplebbits = () => {
|
|||||||
// Check localStorage first
|
// Check localStorage first
|
||||||
const cachedData = getFromLocalStorage();
|
const cachedData = getFromLocalStorage();
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
cacheSubplebbits = cachedData.subplebbits;
|
cacheCommunities = cachedData.communities;
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
setState({
|
setState({
|
||||||
subplebbits: cachedData.subplebbits,
|
communities: cachedData.communities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Still try to fetch fresh data in background (don't await)
|
// Still try to fetch fresh data in background (don't await)
|
||||||
fetchMultisubData()
|
fetchDirectoriesData()
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
cacheSubplebbits = data.subplebbits;
|
cacheCommunities = data.communities;
|
||||||
setState({
|
setState({
|
||||||
subplebbits: data.subplebbits,
|
communities: data.communities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
@@ -131,23 +131,23 @@ export const useDefaultSubplebbits = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No cache, fetch fresh data
|
// No cache, fetch fresh data
|
||||||
const multisub = await fetchMultisubData();
|
const directories = await fetchDirectoriesData();
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
cacheSubplebbits = multisub.subplebbits;
|
cacheCommunities = directories.communities;
|
||||||
setState({
|
setState({
|
||||||
subplebbits: multisub.subplebbits,
|
communities: directories.communities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to load subplebbits:', e);
|
console.warn('Failed to load directories:', e);
|
||||||
// Fallback to vendored data
|
// Fallback to vendored data
|
||||||
const fallbackData = defaultSubplebbitsData as MultisubData;
|
const fallbackData = directoriesData as DirectoriesData;
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
cacheSubplebbits = fallbackData.subplebbits;
|
cacheCommunities = fallbackData.communities;
|
||||||
setState({
|
setState({
|
||||||
subplebbits: fallbackData.subplebbits,
|
communities: fallbackData.communities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
@@ -160,24 +160,24 @@ export const useDefaultSubplebbits = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Always prefer cacheSubplebbits (module-level, stable reference) when available
|
// Always prefer cacheCommunities (module-level, stable reference) when available
|
||||||
// Only use state.subplebbits during initial load before cache is populated
|
// Only use state.communities during initial load before cache is populated
|
||||||
// This ensures a stable reference for memoization in consuming hooks
|
// This ensures a stable reference for memoization in consuming hooks
|
||||||
return cacheSubplebbits || state.subplebbits;
|
return cacheCommunities || state.communities;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDefaultSubplebbitsState = () => {
|
export const useDirectoriesState = () => {
|
||||||
// Use vendored data as fallback to prevent theme flash on first load
|
// Use vendored data as fallback to prevent theme flash on first load
|
||||||
const [state, setState] = useState<DefaultSubplebbitsState>({
|
const [state, setState] = useState<DirectoriesState>({
|
||||||
subplebbits: cacheSubplebbits || (defaultSubplebbitsData as MultisubData).subplebbits,
|
communities: cacheCommunities || (directoriesData as DirectoriesData).communities,
|
||||||
loading: !cacheSubplebbits,
|
loading: !cacheCommunities,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cacheSubplebbits) {
|
if (cacheCommunities) {
|
||||||
setState({
|
setState({
|
||||||
subplebbits: cacheSubplebbits,
|
communities: cacheCommunities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
@@ -191,21 +191,21 @@ export const useDefaultSubplebbitsState = () => {
|
|||||||
// Check localStorage first
|
// Check localStorage first
|
||||||
const cachedData = getFromLocalStorage();
|
const cachedData = getFromLocalStorage();
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
cacheSubplebbits = cachedData.subplebbits;
|
cacheCommunities = cachedData.communities;
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
setState({
|
setState({
|
||||||
subplebbits: cachedData.subplebbits,
|
communities: cachedData.communities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Still try to fetch fresh data in background (don't await)
|
// Still try to fetch fresh data in background (don't await)
|
||||||
fetchMultisubData()
|
fetchDirectoriesData()
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
cacheSubplebbits = data.subplebbits;
|
cacheCommunities = data.communities;
|
||||||
setState({
|
setState({
|
||||||
subplebbits: data.subplebbits,
|
communities: data.communities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
@@ -218,23 +218,23 @@ export const useDefaultSubplebbitsState = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No cache, fetch fresh data
|
// No cache, fetch fresh data
|
||||||
const multisub = await fetchMultisubData();
|
const directories = await fetchDirectoriesData();
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
cacheSubplebbits = multisub.subplebbits;
|
cacheCommunities = directories.communities;
|
||||||
setState({
|
setState({
|
||||||
subplebbits: multisub.subplebbits,
|
communities: directories.communities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to load subplebbits:', e);
|
console.warn('Failed to load directories:', e);
|
||||||
// Fallback to vendored data
|
// Fallback to vendored data
|
||||||
const fallbackData = defaultSubplebbitsData as MultisubData;
|
const fallbackData = directoriesData as DirectoriesData;
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
cacheSubplebbits = fallbackData.subplebbits;
|
cacheCommunities = fallbackData.communities;
|
||||||
setState({
|
setState({
|
||||||
subplebbits: fallbackData.subplebbits,
|
communities: fallbackData.communities,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
@@ -250,13 +250,13 @@ export const useDefaultSubplebbitsState = () => {
|
|||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDefaultSubplebbitAddresses = () => {
|
export const useDirectoryAddresses = () => {
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
return useMemo(() => defaultSubplebbits.map((subplebbit) => subplebbit.address), [defaultSubplebbits]);
|
return useMemo(() => directories.map((community) => community.address), [directories]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useMultisubMetadata = () => {
|
export const useDirectoriesMetadata = () => {
|
||||||
const [metadata, setMetadata] = useState<MultisubMetadata | null>(null);
|
const [metadata, setMetadata] = useState<DirectoriesMetadata | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cacheMetadata) {
|
if (cacheMetadata) {
|
||||||
@@ -270,7 +270,7 @@ export const useMultisubMetadata = () => {
|
|||||||
// Check localStorage first
|
// Check localStorage first
|
||||||
const cachedData = getFromLocalStorage();
|
const cachedData = getFromLocalStorage();
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
const metadata: MultisubMetadata = {
|
const metadata: DirectoriesMetadata = {
|
||||||
title: cachedData.title,
|
title: cachedData.title,
|
||||||
description: cachedData.description,
|
description: cachedData.description,
|
||||||
createdAt: cachedData.createdAt,
|
createdAt: cachedData.createdAt,
|
||||||
@@ -281,10 +281,10 @@ export const useMultisubMetadata = () => {
|
|||||||
setMetadata(metadata);
|
setMetadata(metadata);
|
||||||
}
|
}
|
||||||
// Still try to fetch fresh data in background (don't await)
|
// Still try to fetch fresh data in background (don't await)
|
||||||
fetchMultisubData()
|
fetchDirectoriesData()
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
const freshMetadata: MultisubMetadata = {
|
const freshMetadata: DirectoriesMetadata = {
|
||||||
title: data.title,
|
title: data.title,
|
||||||
description: data.description,
|
description: data.description,
|
||||||
createdAt: data.createdAt,
|
createdAt: data.createdAt,
|
||||||
@@ -301,13 +301,13 @@ export const useMultisubMetadata = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No cache, fetch fresh data
|
// No cache, fetch fresh data
|
||||||
const multisub = await fetchMultisubData();
|
const directories = await fetchDirectoriesData();
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
const metadata: MultisubMetadata = {
|
const metadata: DirectoriesMetadata = {
|
||||||
title: multisub.title,
|
title: directories.title,
|
||||||
description: multisub.description,
|
description: directories.description,
|
||||||
createdAt: multisub.createdAt,
|
createdAt: directories.createdAt,
|
||||||
updatedAt: multisub.updatedAt,
|
updatedAt: directories.updatedAt,
|
||||||
};
|
};
|
||||||
cacheMetadata = metadata;
|
cacheMetadata = metadata;
|
||||||
setMetadata(metadata);
|
setMetadata(metadata);
|
||||||
@@ -315,9 +315,9 @@ export const useMultisubMetadata = () => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to load metadata, using vendored fallback:', e);
|
console.warn('Failed to load metadata, using vendored fallback:', e);
|
||||||
// Fallback to vendored data
|
// Fallback to vendored data
|
||||||
const fallbackData = defaultSubplebbitsData as MultisubData;
|
const fallbackData = directoriesData as DirectoriesData;
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
const metadata: MultisubMetadata = {
|
const metadata: DirectoriesMetadata = {
|
||||||
title: fallbackData.title,
|
title: fallbackData.title,
|
||||||
description: fallbackData.description,
|
description: fallbackData.description,
|
||||||
createdAt: fallbackData.createdAt,
|
createdAt: fallbackData.createdAt,
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { useMemo } from 'react';
|
|
||||||
import { useDefaultSubplebbits } from './use-default-subplebbits';
|
|
||||||
import useAllFeedFilterStore from '../stores/use-all-feed-filter-store';
|
|
||||||
|
|
||||||
export const useFilteredDefaultSubplebbitAddresses = () => {
|
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
|
||||||
const { filter } = useAllFeedFilterStore();
|
|
||||||
|
|
||||||
return useMemo(() => {
|
|
||||||
if (filter === 'all') {
|
|
||||||
return defaultSubplebbits.map((subplebbit) => subplebbit.address);
|
|
||||||
}
|
|
||||||
if (filter === 'nsfw') {
|
|
||||||
return defaultSubplebbits.filter((subplebbit) => subplebbit.nsfw === true).map((subplebbit) => subplebbit.address);
|
|
||||||
}
|
|
||||||
// filter === 'sfw'
|
|
||||||
return defaultSubplebbits.filter((subplebbit) => subplebbit.nsfw !== true).map((subplebbit) => subplebbit.address);
|
|
||||||
}, [defaultSubplebbits, filter]);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useDirectories } from './use-directories';
|
||||||
|
import useAllFeedFilterStore from '../stores/use-all-feed-filter-store';
|
||||||
|
|
||||||
|
export const useFilteredDirectoryAddresses = () => {
|
||||||
|
const directories = useDirectories();
|
||||||
|
const { filter } = useAllFeedFilterStore();
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
if (filter === 'all') {
|
||||||
|
return directories.map((community) => community.address);
|
||||||
|
}
|
||||||
|
if (filter === 'nsfw') {
|
||||||
|
return directories.filter((community) => community.nsfw === true).map((community) => community.address);
|
||||||
|
}
|
||||||
|
// filter === 'sfw'
|
||||||
|
return directories.filter((community) => community.nsfw !== true).map((community) => community.address);
|
||||||
|
}, [directories, filter]);
|
||||||
|
};
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import useThemeStore from '../stores/use-theme-store';
|
import useThemeStore from '../stores/use-theme-store';
|
||||||
import { useDefaultSubplebbits } from './use-default-subplebbits';
|
import { useDirectories } from './use-directories';
|
||||||
import { isAllView, isHomeView, isNotFoundView, isPendingPostView, isSubscriptionsView, isModView } from '../lib/utils/view-utils';
|
import { isAllView, isHomeView, isNotFoundView, isPendingPostView, isSubscriptionsView, isModView } from '../lib/utils/view-utils';
|
||||||
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||||
|
|
||||||
const useInitialTheme = (pendingPostSubplebbitAddress?: string) => {
|
const useInitialTheme = (pendingPostSubplebbitAddress?: string) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { subplebbitAddress: paramsSubplebbitAddress, accountCommentIndex } = useParams<{ subplebbitAddress: string; accountCommentIndex?: string }>();
|
const { communityAddress: paramsSubplebbitAddress, accountCommentIndex } = useParams<{ communityAddress: string; accountCommentIndex?: string }>();
|
||||||
const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined;
|
const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined;
|
||||||
const pendingPost = useAccountComment({ commentIndex });
|
const pendingPost = useAccountComment({ commentIndex });
|
||||||
// Subscribe to the actual themes data, not just functions
|
// Subscribe to the actual themes data, not just functions
|
||||||
const themes = useThemeStore((state) => state.themes);
|
const themes = useThemeStore((state) => state.themes);
|
||||||
const subplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const isInHomeView = isHomeView(location.pathname);
|
const isInHomeView = isHomeView(location.pathname);
|
||||||
const isInNotFoundView = isNotFoundView(location.pathname, params);
|
const isInNotFoundView = isNotFoundView(location.pathname, params);
|
||||||
@@ -25,10 +25,10 @@ const useInitialTheme = (pendingPostSubplebbitAddress?: string) => {
|
|||||||
let theme = 'yotsuba';
|
let theme = 'yotsuba';
|
||||||
|
|
||||||
if (isInPendingPostView) {
|
if (isInPendingPostView) {
|
||||||
const subplebbitAddress = pendingPostSubplebbitAddress || pendingPost?.subplebbitAddress;
|
const communityAddress = pendingPostSubplebbitAddress || pendingPost?.communityAddress;
|
||||||
if (subplebbitAddress) {
|
if (communityAddress) {
|
||||||
const subplebbit = subplebbits.find((s) => s.address === subplebbitAddress);
|
const community = directories.find((s) => s.address === communityAddress);
|
||||||
if (subplebbit?.nsfw) {
|
if (community?.nsfw) {
|
||||||
theme = themes.nsfw || 'yotsuba';
|
theme = themes.nsfw || 'yotsuba';
|
||||||
} else {
|
} else {
|
||||||
theme = themes.sfw || 'yotsuba-b';
|
theme = themes.sfw || 'yotsuba-b';
|
||||||
@@ -41,8 +41,8 @@ const useInitialTheme = (pendingPostSubplebbitAddress?: string) => {
|
|||||||
} else if (isInHomeView || isInNotFoundView) {
|
} else if (isInHomeView || isInNotFoundView) {
|
||||||
theme = 'yotsuba';
|
theme = 'yotsuba';
|
||||||
} else if (paramsSubplebbitAddress) {
|
} else if (paramsSubplebbitAddress) {
|
||||||
const subplebbit = subplebbits.find((s) => s.address === paramsSubplebbitAddress);
|
const community = directories.find((s) => s.address === paramsSubplebbitAddress);
|
||||||
if (subplebbit?.nsfw) {
|
if (community?.nsfw) {
|
||||||
theme = themes.nsfw || 'yotsuba';
|
theme = themes.nsfw || 'yotsuba';
|
||||||
} else {
|
} else {
|
||||||
theme = themes.sfw || 'yotsuba-b';
|
theme = themes.sfw || 'yotsuba-b';
|
||||||
@@ -59,7 +59,7 @@ const useInitialTheme = (pendingPostSubplebbitAddress?: string) => {
|
|||||||
isInNotFoundView,
|
isInNotFoundView,
|
||||||
paramsSubplebbitAddress,
|
paramsSubplebbitAddress,
|
||||||
themes,
|
themes,
|
||||||
subplebbits,
|
directories,
|
||||||
pendingPostSubplebbitAddress,
|
pendingPostSubplebbitAddress,
|
||||||
pendingPost,
|
pendingPost,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useDefaultSubplebbits } from './use-default-subplebbits';
|
import { useDirectories } from './use-directories';
|
||||||
import { getSubplebbitAddress, getBoardPath } from '../lib/utils/route-utils';
|
import { getSubplebbitAddress, getBoardPath } from '../lib/utils/route-utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to resolve boardIdentifier from URL params to subplebbitAddress
|
* Hook to resolve boardIdentifier from URL params to subplebbitAddress
|
||||||
* Handles both directory codes (e.g., "biz") and full addresses (e.g., "someboard.eth")
|
* Handles both directory codes (e.g., "biz") and full addresses (e.g., "someboard.eth")
|
||||||
*
|
*
|
||||||
* Performance: Uses useMemo to avoid recalculating when params/defaultSubplebbits haven't changed.
|
* Performance: Uses useMemo to avoid recalculating when params/directories haven't changed.
|
||||||
* The defaultSubplebbits reference is stable (from cache) after initial load, so memoization works effectively.
|
* The directories reference is stable (from cache) after initial load, so memoization works effectively.
|
||||||
*/
|
*/
|
||||||
export const useResolvedSubplebbitAddress = (): string | undefined => {
|
export const useResolvedSubplebbitAddress = (): string | undefined => {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
// Try boardIdentifier first (new format), then subplebbitAddress (old format for backward compatibility)
|
// Try boardIdentifier first (new format), then subplebbitAddress (old format for backward compatibility)
|
||||||
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
const boardIdentifier = params.boardIdentifier || params.subplebbitAddress;
|
||||||
@@ -24,18 +24,18 @@ export const useResolvedSubplebbitAddress = (): string | undefined => {
|
|||||||
|
|
||||||
// Resolve directory code to address if needed
|
// Resolve directory code to address if needed
|
||||||
// getSubplebbitAddress uses internal caching, so this is efficient
|
// getSubplebbitAddress uses internal caching, so this is efficient
|
||||||
return getSubplebbitAddress(boardIdentifier, defaultSubplebbits);
|
return getSubplebbitAddress(boardIdentifier, directories);
|
||||||
}, [boardIdentifier, defaultSubplebbits]);
|
}, [boardIdentifier, directories]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to get the board path (directory code or address) for use in links
|
* Hook to get the board path (directory code or address) for use in links
|
||||||
*
|
*
|
||||||
* Performance: Uses useMemo to avoid recalculating when subplebbitAddress/defaultSubplebbits haven't changed.
|
* Performance: Uses useMemo to avoid recalculating when subplebbitAddress/directories haven't changed.
|
||||||
* The defaultSubplebbits reference is stable (from cache) after initial load, so memoization works effectively.
|
* The directories reference is stable (from cache) after initial load, so memoization works effectively.
|
||||||
*/
|
*/
|
||||||
export const useBoardPath = (subplebbitAddress: string | undefined): string | undefined => {
|
export const useBoardPath = (subplebbitAddress: string | undefined): string | undefined => {
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
if (!subplebbitAddress) {
|
if (!subplebbitAddress) {
|
||||||
@@ -43,6 +43,6 @@ export const useBoardPath = (subplebbitAddress: string | undefined): string | un
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getBoardPath uses internal caching, so this is efficient
|
// getBoardPath uses internal caching, so this is efficient
|
||||||
return getBoardPath(subplebbitAddress, defaultSubplebbits);
|
return getBoardPath(subplebbitAddress, directories);
|
||||||
}, [subplebbitAddress, defaultSubplebbits]);
|
}, [subplebbitAddress, directories]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect, useCallback, useMemo } from 'react';
|
|||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import { isAllView, isSubscriptionsView, isModView } from '../lib/utils/view-utils';
|
import { isAllView, isSubscriptionsView, isModView } from '../lib/utils/view-utils';
|
||||||
import useThemeStore from '../stores/use-theme-store';
|
import useThemeStore from '../stores/use-theme-store';
|
||||||
import { useDefaultSubplebbits } from './use-default-subplebbits';
|
import { useDirectories } from './use-directories';
|
||||||
import { useResolvedSubplebbitAddress } from './use-resolved-subplebbit-address';
|
import { useResolvedSubplebbitAddress } from './use-resolved-subplebbit-address';
|
||||||
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
import { useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||||
import useSpecialThemeStore from '../stores/use-special-theme-store';
|
import useSpecialThemeStore from '../stores/use-special-theme-store';
|
||||||
@@ -29,7 +29,7 @@ const useTheme = (): [string, (theme: string) => void] => {
|
|||||||
const setThemeStore = useThemeStore((state) => state.setTheme);
|
const setThemeStore = useThemeStore((state) => state.setTheme);
|
||||||
// Subscribe to the actual themes data, not just the getter function
|
// Subscribe to the actual themes data, not just the getter function
|
||||||
const themes = useThemeStore((state) => state.themes);
|
const themes = useThemeStore((state) => state.themes);
|
||||||
const subplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const isInAllView = isAllView(location.pathname);
|
const isInAllView = isAllView(location.pathname);
|
||||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||||
@@ -64,7 +64,7 @@ const useTheme = (): [string, (theme: string) => void] => {
|
|||||||
if (isInAllView || isInSubscriptionsView || isInModView) {
|
if (isInAllView || isInSubscriptionsView || isInModView) {
|
||||||
storedTheme = themes.nsfw;
|
storedTheme = themes.nsfw;
|
||||||
} else if (subplebbitAddress) {
|
} else if (subplebbitAddress) {
|
||||||
const subplebbit = subplebbits.find((s) => s.address === subplebbitAddress);
|
const subplebbit = directories.find((s) => s.address === subplebbitAddress);
|
||||||
if (subplebbit?.nsfw) {
|
if (subplebbit?.nsfw) {
|
||||||
storedTheme = themes.nsfw;
|
storedTheme = themes.nsfw;
|
||||||
} else {
|
} else {
|
||||||
@@ -73,7 +73,7 @@ const useTheme = (): [string, (theme: string) => void] => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return storedTheme || 'yotsuba';
|
return storedTheme || 'yotsuba';
|
||||||
}, [location.pathname, isEnabled, isInAllView, isInSubscriptionsView, isInModView, subplebbitAddress, subplebbits, themes]);
|
}, [location.pathname, isEnabled, isInAllView, isInSubscriptionsView, isInModView, subplebbitAddress, directories, themes]);
|
||||||
|
|
||||||
// Update DOM class when theme changes
|
// Update DOM class when theme changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -85,7 +85,7 @@ const useTheme = (): [string, (theme: string) => void] => {
|
|||||||
if (isInAllView || isInSubscriptionsView || isInModView) {
|
if (isInAllView || isInSubscriptionsView || isInModView) {
|
||||||
await setThemeStore('nsfw', newTheme);
|
await setThemeStore('nsfw', newTheme);
|
||||||
} else if (subplebbitAddress) {
|
} else if (subplebbitAddress) {
|
||||||
const subplebbit = subplebbits.find((s) => s.address === subplebbitAddress);
|
const subplebbit = directories.find((s) => s.address === subplebbitAddress);
|
||||||
if (subplebbit?.nsfw) {
|
if (subplebbit?.nsfw) {
|
||||||
await setThemeStore('nsfw', newTheme);
|
await setThemeStore('nsfw', newTheme);
|
||||||
} else {
|
} else {
|
||||||
@@ -93,7 +93,7 @@ const useTheme = (): [string, (theme: string) => void] => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[isInAllView, isInSubscriptionsView, isInModView, subplebbitAddress, subplebbits, setThemeStore],
|
[isInAllView, isInSubscriptionsView, isInModView, subplebbitAddress, directories, setThemeStore],
|
||||||
);
|
);
|
||||||
|
|
||||||
return [currentTheme, setSubplebbitTheme];
|
return [currentTheme, setSubplebbitTheme];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MultisubSubplebbit } from '../../hooks/use-default-subplebbits';
|
import { DirectoryCommunity } from '../../hooks/use-directories';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract directory short code from title (e.g., "/biz/ - Business & Finance" -> "biz")
|
* Extract directory short code from title (e.g., "/biz/ - Business & Finance" -> "biz")
|
||||||
@@ -9,79 +9,79 @@ export const extractDirectoryFromTitle = (title: string): string | null => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Cache for directory-to-address map
|
// Cache for directory-to-address map
|
||||||
let cachedSubplebbitsForDirectory: MultisubSubplebbit[] | null = null;
|
let cachedCommunitiesForDirectory: DirectoryCommunity[] | null = null;
|
||||||
let cachedDirectoryToAddressMap: Map<string, string> | null = null;
|
let cachedDirectoryToAddressMap: Map<string, string> | null = null;
|
||||||
|
|
||||||
// Cache for address-to-directory map
|
// Cache for address-to-directory map
|
||||||
let cachedSubplebbitsForAddress: MultisubSubplebbit[] | null = null;
|
let cachedCommunitiesForAddress: DirectoryCommunity[] | null = null;
|
||||||
let cachedAddressToDirectoryMap: Map<string, string> | null = null;
|
let cachedAddressToDirectoryMap: Map<string, string> | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a map from directory codes to subplebbit addresses
|
* Create a map from directory codes to community addresses
|
||||||
* Uses caching to avoid recreating the map when subplebbits array hasn't changed
|
* Uses caching to avoid recreating the map when communities array hasn't changed
|
||||||
*/
|
*/
|
||||||
export const getDirectoryToAddressMap = (subplebbits: MultisubSubplebbit[]): Map<string, string> => {
|
export const getDirectoryToAddressMap = (communities: DirectoryCommunity[]): Map<string, string> => {
|
||||||
// Check if we can use cached map (same array reference)
|
// Check if we can use cached map (same array reference)
|
||||||
if (cachedDirectoryToAddressMap && cachedSubplebbitsForDirectory === subplebbits) {
|
if (cachedDirectoryToAddressMap && cachedCommunitiesForDirectory === communities) {
|
||||||
return cachedDirectoryToAddressMap;
|
return cachedDirectoryToAddressMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const map = new Map<string, string>();
|
const map = new Map<string, string>();
|
||||||
for (const subplebbit of subplebbits) {
|
for (const community of communities) {
|
||||||
if (subplebbit.title) {
|
if (community.title) {
|
||||||
const directory = extractDirectoryFromTitle(subplebbit.title);
|
const directory = extractDirectoryFromTitle(community.title);
|
||||||
if (directory && subplebbit.address) {
|
if (directory && community.address) {
|
||||||
map.set(directory, subplebbit.address);
|
map.set(directory, community.address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the map and array reference
|
// Cache the map and array reference
|
||||||
cachedDirectoryToAddressMap = map;
|
cachedDirectoryToAddressMap = map;
|
||||||
cachedSubplebbitsForDirectory = subplebbits;
|
cachedCommunitiesForDirectory = communities;
|
||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a map from subplebbit addresses to directory codes
|
* Create a map from community addresses to directory codes
|
||||||
* Uses caching to avoid recreating the map when subplebbits array hasn't changed
|
* Uses caching to avoid recreating the map when communities array hasn't changed
|
||||||
*/
|
*/
|
||||||
export const getAddressToDirectoryMap = (subplebbits: MultisubSubplebbit[]): Map<string, string> => {
|
export const getAddressToDirectoryMap = (communities: DirectoryCommunity[]): Map<string, string> => {
|
||||||
// Check if we can use cached map (same array reference)
|
// Check if we can use cached map (same array reference)
|
||||||
if (cachedAddressToDirectoryMap && cachedSubplebbitsForAddress === subplebbits) {
|
if (cachedAddressToDirectoryMap && cachedCommunitiesForAddress === communities) {
|
||||||
return cachedAddressToDirectoryMap;
|
return cachedAddressToDirectoryMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const map = new Map<string, string>();
|
const map = new Map<string, string>();
|
||||||
for (const subplebbit of subplebbits) {
|
for (const community of communities) {
|
||||||
if (subplebbit.title && subplebbit.address) {
|
if (community.title && community.address) {
|
||||||
const directory = extractDirectoryFromTitle(subplebbit.title);
|
const directory = extractDirectoryFromTitle(community.title);
|
||||||
if (directory) {
|
if (directory) {
|
||||||
map.set(subplebbit.address, directory);
|
map.set(community.address, directory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the map and array reference
|
// Cache the map and array reference
|
||||||
cachedAddressToDirectoryMap = map;
|
cachedAddressToDirectoryMap = map;
|
||||||
cachedSubplebbitsForAddress = subplebbits;
|
cachedCommunitiesForAddress = communities;
|
||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert subplebbit address to URL path (directory code if available, otherwise full address)
|
* Convert community address to URL path (directory code if available, otherwise full address)
|
||||||
*/
|
*/
|
||||||
export const getBoardPath = (subplebbitAddress: string, subplebbits: MultisubSubplebbit[]): string => {
|
export const getBoardPath = (communityAddress: string, communities: DirectoryCommunity[]): string => {
|
||||||
const addressToDirectory = getAddressToDirectoryMap(subplebbits);
|
const addressToDirectory = getAddressToDirectoryMap(communities);
|
||||||
const directory = addressToDirectory.get(subplebbitAddress);
|
const directory = addressToDirectory.get(communityAddress);
|
||||||
return directory || subplebbitAddress;
|
return directory || communityAddress;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert URL path (directory code or address) to subplebbit address
|
* Convert URL path (directory code or address) to community address
|
||||||
*/
|
*/
|
||||||
export const getSubplebbitAddress = (boardIdentifier: string, subplebbits: MultisubSubplebbit[]): string => {
|
export const getSubplebbitAddress = (boardIdentifier: string, communities: DirectoryCommunity[]): string => {
|
||||||
const directoryToAddress = getDirectoryToAddressMap(subplebbits);
|
const directoryToAddress = getDirectoryToAddressMap(communities);
|
||||||
|
|
||||||
// Check if it's a directory code
|
// Check if it's a directory code
|
||||||
const address = directoryToAddress.get(boardIdentifier);
|
const address = directoryToAddress.get(boardIdentifier);
|
||||||
@@ -96,8 +96,8 @@ export const getSubplebbitAddress = (boardIdentifier: string, subplebbits: Multi
|
|||||||
/**
|
/**
|
||||||
* Check if an identifier is a directory short code
|
* Check if an identifier is a directory short code
|
||||||
*/
|
*/
|
||||||
export const isDirectoryBoard = (identifier: string, subplebbits: MultisubSubplebbit[]): boolean => {
|
export const isDirectoryBoard = (identifier: string, communities: DirectoryCommunity[]): boolean => {
|
||||||
const directoryToAddress = getDirectoryToAddressMap(subplebbits);
|
const directoryToAddress = getDirectoryToAddressMap(communities);
|
||||||
return directoryToAddress.has(identifier);
|
return directoryToAddress.has(identifier);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+11
-32
@@ -7,8 +7,8 @@ import { Trans, useTranslation } from 'react-i18next';
|
|||||||
import styles from './board.module.css';
|
import styles from './board.module.css';
|
||||||
import { shouldShowSnow } from '../../lib/snow';
|
import { shouldShowSnow } from '../../lib/snow';
|
||||||
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||||
import { useDefaultSubplebbitAddresses, useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectoryAddresses, useDirectories } from '../../hooks/use-directories';
|
||||||
import { useFilteredDefaultSubplebbitAddresses } from '../../hooks/use-filtered-default-subplebbit-addresses';
|
import { useFilteredDirectoryAddresses } from '../../hooks/use-filtered-directory-addresses';
|
||||||
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
|
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
|
||||||
import { useFeedStateString } from '../../hooks/use-state-string';
|
import { useFeedStateString } from '../../hooks/use-state-string';
|
||||||
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
|
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
|
||||||
@@ -194,18 +194,18 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
|
|||||||
const isInSubscriptionsView = viewType ? viewType === 'subs' : false;
|
const isInSubscriptionsView = viewType ? viewType === 'subs' : false;
|
||||||
const isInModView = viewType ? viewType === 'mod' : false;
|
const isInModView = viewType ? viewType === 'mod' : false;
|
||||||
|
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const resolvedAddressFromUrl = useResolvedSubplebbitAddress();
|
const resolvedAddressFromUrl = useResolvedSubplebbitAddress();
|
||||||
const subplebbitAddress = useMemo(() => {
|
const subplebbitAddress = useMemo(() => {
|
||||||
if (boardIdentifierProp) {
|
if (boardIdentifierProp) {
|
||||||
return getSubplebbitAddress(boardIdentifierProp, defaultSubplebbits);
|
return getSubplebbitAddress(boardIdentifierProp, directories);
|
||||||
}
|
}
|
||||||
return resolvedAddressFromUrl;
|
return resolvedAddressFromUrl;
|
||||||
}, [boardIdentifierProp, defaultSubplebbits, resolvedAddressFromUrl]);
|
}, [boardIdentifierProp, directories, resolvedAddressFromUrl]);
|
||||||
|
|
||||||
const boardPath = useBoardPath(subplebbitAddress);
|
const boardPath = useBoardPath(subplebbitAddress);
|
||||||
const defaultSubplebbitAddresses = useDefaultSubplebbitAddresses();
|
const directoryAddresses = useDirectoryAddresses();
|
||||||
const filteredDefaultSubplebbitAddresses = useFilteredDefaultSubplebbitAddresses();
|
const filteredDirectoryAddresses = useFilteredDirectoryAddresses();
|
||||||
|
|
||||||
const account = useAccount();
|
const account = useAccount();
|
||||||
const subscriptions = account?.subscriptions;
|
const subscriptions = account?.subscriptions;
|
||||||
@@ -215,7 +215,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
|
|||||||
|
|
||||||
const subplebbitAddresses = useMemo(() => {
|
const subplebbitAddresses = useMemo(() => {
|
||||||
if (isInAllView) {
|
if (isInAllView) {
|
||||||
return filteredDefaultSubplebbitAddresses;
|
return filteredDirectoryAddresses;
|
||||||
}
|
}
|
||||||
if (isInSubscriptionsView) {
|
if (isInSubscriptionsView) {
|
||||||
return subscriptions || [];
|
return subscriptions || [];
|
||||||
@@ -224,16 +224,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
|
|||||||
return accountSubplebbitAddresses;
|
return accountSubplebbitAddresses;
|
||||||
}
|
}
|
||||||
return [subplebbitAddress];
|
return [subplebbitAddress];
|
||||||
}, [
|
}, [isInAllView, isInSubscriptionsView, isInModView, subplebbitAddress, directoryAddresses, filteredDirectoryAddresses, subscriptions, accountSubplebbitAddresses]);
|
||||||
isInAllView,
|
|
||||||
isInSubscriptionsView,
|
|
||||||
isInModView,
|
|
||||||
subplebbitAddress,
|
|
||||||
defaultSubplebbitAddresses,
|
|
||||||
filteredDefaultSubplebbitAddresses,
|
|
||||||
subscriptions,
|
|
||||||
accountSubplebbitAddresses,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const { sortType } = useSortingStore();
|
const { sortType } = useSortingStore();
|
||||||
const { timeFilterSeconds: timeFilterSecondsFromHook, timeFilterName: timeFilterNameFromHook } = useTimeFilter();
|
const { timeFilterSeconds: timeFilterSecondsFromHook, timeFilterName: timeFilterNameFromHook } = useTimeFilter();
|
||||||
@@ -442,7 +433,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isVisible) return;
|
if (!isVisible) return;
|
||||||
const boardIdentifier = params.boardIdentifier || boardIdentifierProp;
|
const boardIdentifier = params.boardIdentifier || boardIdentifierProp;
|
||||||
const isDirectory = boardIdentifier ? isDirectoryBoard(boardIdentifier, defaultSubplebbits) : false;
|
const isDirectory = boardIdentifier ? isDirectoryBoard(boardIdentifier, directories) : false;
|
||||||
|
|
||||||
let boardTitle: string;
|
let boardTitle: string;
|
||||||
if (isInAllView) {
|
if (isInAllView) {
|
||||||
@@ -457,19 +448,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
|
|||||||
boardTitle = title ? title : shortAddress || subplebbitAddress || '';
|
boardTitle = title ? title : shortAddress || subplebbitAddress || '';
|
||||||
}
|
}
|
||||||
document.title = boardTitle + ' - 5chan';
|
document.title = boardTitle + ' - 5chan';
|
||||||
}, [
|
}, [title, shortAddress, subplebbitAddress, isVisible, params.boardIdentifier, boardIdentifierProp, directories, isInAllView, isInSubscriptionsView, isInModView, t]);
|
||||||
title,
|
|
||||||
shortAddress,
|
|
||||||
subplebbitAddress,
|
|
||||||
isVisible,
|
|
||||||
params.boardIdentifier,
|
|
||||||
boardIdentifierProp,
|
|
||||||
defaultSubplebbits,
|
|
||||||
isInAllView,
|
|
||||||
isInSubscriptionsView,
|
|
||||||
isInModView,
|
|
||||||
t,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const shouldShowErrorToUser = subplebbitError?.message && feed.length === 0;
|
const shouldShowErrorToUser = subplebbitError?.message && feed.length === 0;
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { Comment, useAccount, useFeed, useSubplebbit, useBlock, useAccountCommen
|
|||||||
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
||||||
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||||
import useCatalogFeedRows from '../../hooks/use-catalog-feed-rows';
|
import useCatalogFeedRows from '../../hooks/use-catalog-feed-rows';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { useFilteredDefaultSubplebbitAddresses } from '../../hooks/use-filtered-default-subplebbit-addresses';
|
import { useFilteredDirectoryAddresses } from '../../hooks/use-filtered-directory-addresses';
|
||||||
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
|
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
|
||||||
import { useFeedStateString } from '../../hooks/use-state-string';
|
import { useFeedStateString } from '../../hooks/use-state-string';
|
||||||
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
|
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
|
||||||
@@ -302,32 +302,32 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
|
|||||||
const isInAllView = viewType ? viewType === 'all' : false;
|
const isInAllView = viewType ? viewType === 'all' : false;
|
||||||
const isInSubscriptionsView = viewType ? viewType === 'subs' : false;
|
const isInSubscriptionsView = viewType ? viewType === 'subs' : false;
|
||||||
|
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const resolvedAddressFromUrl = useResolvedSubplebbitAddress();
|
const resolvedAddressFromUrl = useResolvedSubplebbitAddress();
|
||||||
const subplebbitAddress = useMemo(() => {
|
const subplebbitAddress = useMemo(() => {
|
||||||
if (boardIdentifierProp) {
|
if (boardIdentifierProp) {
|
||||||
return getSubplebbitAddress(boardIdentifierProp, defaultSubplebbits);
|
return getSubplebbitAddress(boardIdentifierProp, directories);
|
||||||
}
|
}
|
||||||
return resolvedAddressFromUrl;
|
return resolvedAddressFromUrl;
|
||||||
}, [boardIdentifierProp, defaultSubplebbits, resolvedAddressFromUrl]);
|
}, [boardIdentifierProp, directories, resolvedAddressFromUrl]);
|
||||||
|
|
||||||
const boardPath = useBoardPath(subplebbitAddress);
|
const boardPath = useBoardPath(subplebbitAddress);
|
||||||
const { showTextOnlyThreads, filterItems, searchText, clearMatchedFilters } = useCatalogFiltersStore();
|
const { showTextOnlyThreads, filterItems, searchText, clearMatchedFilters } = useCatalogFiltersStore();
|
||||||
|
|
||||||
const account = useAccount();
|
const account = useAccount();
|
||||||
const subscriptions = account?.subscriptions;
|
const subscriptions = account?.subscriptions;
|
||||||
const filteredDefaultSubplebbitAddresses = useFilteredDefaultSubplebbitAddresses();
|
const filteredDirectoryAddresses = useFilteredDirectoryAddresses();
|
||||||
|
|
||||||
const subplebbitAddresses = useMemo(() => {
|
const subplebbitAddresses = useMemo(() => {
|
||||||
if (isInAllView) {
|
if (isInAllView) {
|
||||||
return filteredDefaultSubplebbitAddresses;
|
return filteredDirectoryAddresses;
|
||||||
}
|
}
|
||||||
if (isInSubscriptionsView) {
|
if (isInSubscriptionsView) {
|
||||||
return (subscriptions || []).filter(Boolean); // Filter out any undefined/null values
|
return (subscriptions || []).filter(Boolean); // Filter out any undefined/null values
|
||||||
}
|
}
|
||||||
// Only include subplebbitAddress if it's defined
|
// Only include subplebbitAddress if it's defined
|
||||||
return subplebbitAddress ? [subplebbitAddress] : [];
|
return subplebbitAddress ? [subplebbitAddress] : [];
|
||||||
}, [isInAllView, isInSubscriptionsView, subplebbitAddress, filteredDefaultSubplebbitAddresses, subscriptions]);
|
}, [isInAllView, isInSubscriptionsView, subplebbitAddress, filteredDirectoryAddresses, subscriptions]);
|
||||||
|
|
||||||
const { imageSize } = useCatalogStyleStore();
|
const { imageSize } = useCatalogStyleStore();
|
||||||
const columnWidth = imageSize === 'Large' ? 270 : 180;
|
const columnWidth = imageSize === 'Large' ? 270 : 180;
|
||||||
@@ -601,7 +601,7 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isVisible) return;
|
if (!isVisible) return;
|
||||||
const boardIdentifier = params.boardIdentifier || boardIdentifierProp;
|
const boardIdentifier = params.boardIdentifier || boardIdentifierProp;
|
||||||
const isDirectory = boardIdentifier ? isDirectoryBoard(boardIdentifier, defaultSubplebbits) : false;
|
const isDirectory = boardIdentifier ? isDirectoryBoard(boardIdentifier, directories) : false;
|
||||||
|
|
||||||
let documentTitle: string;
|
let documentTitle: string;
|
||||||
if (isInAllView) {
|
if (isInAllView) {
|
||||||
@@ -614,7 +614,7 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
|
|||||||
documentTitle = title ? title : shortAddress || subplebbitAddress || '';
|
documentTitle = title ? title : shortAddress || subplebbitAddress || '';
|
||||||
}
|
}
|
||||||
document.title = documentTitle + ` - ${t('catalog')} - 5chan`;
|
document.title = documentTitle + ` - ${t('catalog')} - 5chan`;
|
||||||
}, [title, shortAddress, subplebbitAddress, isInAllView, isInSubscriptionsView, t, isVisible, params.boardIdentifier, boardIdentifierProp, defaultSubplebbits]);
|
}, [title, shortAddress, subplebbitAddress, isInAllView, isInSubscriptionsView, t, isVisible, params.boardIdentifier, boardIdentifierProp, directories]);
|
||||||
|
|
||||||
// Clear matched filters when component mounts or when subplebbit changes
|
// Clear matched filters when component mounts or when subplebbit changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDefaultSubplebbitsState, useDefaultSubplebbits, MultisubSubplebbit } from '../../../hooks/use-default-subplebbits';
|
import { useDirectoriesState, useDirectories, DirectoryCommunity } from '../../../hooks/use-directories';
|
||||||
import { getBoardPath } from '../../../lib/utils/route-utils';
|
import { getBoardPath } from '../../../lib/utils/route-utils';
|
||||||
import useDisclaimerModalStore from '../../../stores/use-disclaimer-modal-store';
|
import useDisclaimerModalStore from '../../../stores/use-disclaimer-modal-store';
|
||||||
import useDirectoryModalStore from '../../../stores/use-directory-modal-store';
|
import useDirectoryModalStore from '../../../stores/use-directory-modal-store';
|
||||||
@@ -9,7 +9,7 @@ import BoardsFilterModal from './boards-filter-modal';
|
|||||||
import styles from '../home.module.css';
|
import styles from '../home.module.css';
|
||||||
|
|
||||||
// Helper function to find board address by matching title pattern
|
// Helper function to find board address by matching title pattern
|
||||||
const findBoardAddress = (multisub: MultisubSubplebbit[], titlePattern: string): string | null => {
|
const findBoardAddress = (multisub: DirectoryCommunity[], titlePattern: string): string | null => {
|
||||||
const entry = multisub.find((ms) => ms.title === titlePattern);
|
const entry = multisub.find((ms) => ms.title === titlePattern);
|
||||||
return entry?.address || null;
|
return entry?.address || null;
|
||||||
};
|
};
|
||||||
@@ -27,25 +27,25 @@ const NSFWBadge = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const BoardsList = ({ multisub }: { multisub: MultisubSubplebbit[] }) => {
|
const BoardsList = ({ multisub }: { multisub: DirectoryCommunity[] }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { error } = useDefaultSubplebbitsState();
|
const { error } = useDirectoriesState();
|
||||||
const { showDisclaimerModal } = useDisclaimerModalStore();
|
const { showDisclaimerModal } = useDisclaimerModalStore();
|
||||||
const { openDirectoryModal } = useDirectoryModalStore();
|
const { openDirectoryModal } = useDirectoryModalStore();
|
||||||
const { useCatalogLinks, boardFilter } = useBoardsFilterStore();
|
const { useCatalogLinks, boardFilter } = useBoardsFilterStore();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const handleLinkClick = (e: React.MouseEvent<HTMLAnchorElement>, address: string) => {
|
const handleLinkClick = (e: React.MouseEvent<HTMLAnchorElement>, address: string) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const boardPath = getBoardPath(address, defaultSubplebbits);
|
const boardPath = getBoardPath(address, directories);
|
||||||
showDisclaimerModal(address, navigate, boardPath);
|
showDisclaimerModal(address, navigate, boardPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper to generate link URL with optional catalog suffix
|
// Helper to generate link URL with optional catalog suffix
|
||||||
const getBoardLink = (address: string | null): string => {
|
const getBoardLink = (address: string | null): string => {
|
||||||
if (!address) return '#';
|
if (!address) return '#';
|
||||||
const boardPath = getBoardPath(address, defaultSubplebbits);
|
const boardPath = getBoardPath(address, directories);
|
||||||
return `/${boardPath}${useCatalogLinks ? '/catalog' : ''}`;
|
return `/${boardPath}${useCatalogLinks ? '/catalog' : ''}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+14
-14
@@ -3,7 +3,7 @@ import { Link, useNavigate } from 'react-router-dom';
|
|||||||
import { Trans, useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
import { useSubplebbits } from '@plebbit/plebbit-react-hooks';
|
import { useSubplebbits } from '@plebbit/plebbit-react-hooks';
|
||||||
import styles from './home.module.css';
|
import styles from './home.module.css';
|
||||||
import { useDefaultSubplebbits, useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
|
import { useDirectories, useDirectoryAddresses } from '../../hooks/use-directories';
|
||||||
import { SubplebbitStatsCollector, useSubplebbitsStatsStore } from '../../hooks/use-subplebbits-stats';
|
import { SubplebbitStatsCollector, useSubplebbitsStatsStore } from '../../hooks/use-subplebbits-stats';
|
||||||
import PopularThreadsBox from './popular-threads-box';
|
import PopularThreadsBox from './popular-threads-box';
|
||||||
import BoardsList from './boards-list';
|
import BoardsList from './boards-list';
|
||||||
@@ -14,19 +14,19 @@ import DirectoryModal from '../../components/directory-modal';
|
|||||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
// https://github.com/plebbit/lists/blob/master/5chan-multisub.json
|
// https://github.com/plebbit/lists/blob/master/5chan-directories.json
|
||||||
|
|
||||||
const SearchBar = () => {
|
const SearchBar = () => {
|
||||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const handleSearchSubmit = (e: FormEvent) => {
|
const handleSearchSubmit = (e: FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const searchInput = searchInputRef.current?.value;
|
const searchInput = searchInputRef.current?.value;
|
||||||
if (searchInput) {
|
if (searchInput) {
|
||||||
const boardPath = getBoardPath(searchInput, defaultSubplebbits);
|
const boardPath = getBoardPath(searchInput, directories);
|
||||||
navigate(`/${boardPath}`);
|
navigate(`/${boardPath}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -73,7 +73,7 @@ const InfoBox = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Stats = ({ subplebbitAddresses }: { subplebbitAddresses: string[] }) => {
|
const Stats = ({ directoryAddresses }: { directoryAddresses: string[] }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const subplebbitsStats = useSubplebbitsStatsStore((state) => state.subplebbitsStats);
|
const subplebbitsStats = useSubplebbitsStatsStore((state) => state.subplebbitsStats);
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ const Stats = ({ subplebbitAddresses }: { subplebbitAddresses: string[] }) => {
|
|||||||
let currentUsers = 0;
|
let currentUsers = 0;
|
||||||
let boardsTracked = 0;
|
let boardsTracked = 0;
|
||||||
|
|
||||||
subplebbitAddresses.forEach((address) => {
|
directoryAddresses.forEach((address) => {
|
||||||
const stat = subplebbitsStats[address];
|
const stat = subplebbitsStats[address];
|
||||||
if (stat) {
|
if (stat) {
|
||||||
totalPosts += stat.allPostCount || 0;
|
totalPosts += stat.allPostCount || 0;
|
||||||
@@ -92,12 +92,12 @@ const Stats = ({ subplebbitAddresses }: { subplebbitAddresses: string[] }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return { totalPosts, currentUsers, boardsTracked };
|
return { totalPosts, currentUsers, boardsTracked };
|
||||||
}, [subplebbitsStats, subplebbitAddresses]);
|
}, [subplebbitsStats, directoryAddresses]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Render collectors to fetch stats for each subplebbit */}
|
{/* Render collectors to fetch stats for each subplebbit */}
|
||||||
{subplebbitAddresses.map((address) => (
|
{directoryAddresses.map((address) => (
|
||||||
<SubplebbitStatsCollector key={address} subplebbitAddress={address} />
|
<SubplebbitStatsCollector key={address} subplebbitAddress={address} />
|
||||||
))}
|
))}
|
||||||
<div className={styles.box}>
|
<div className={styles.box}>
|
||||||
@@ -192,9 +192,9 @@ export const HomeLogo = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const subplebbitAddresses = useDefaultSubplebbitAddresses();
|
const directoryAddresses = useDirectoryAddresses();
|
||||||
const { subplebbits } = useSubplebbits({ subplebbitAddresses });
|
const { subplebbits } = useSubplebbits({ subplebbitAddresses: directoryAddresses });
|
||||||
const { closeDirectoryModal } = useDirectoryModalStore();
|
const { closeDirectoryModal } = useDirectoryModalStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -216,9 +216,9 @@ const Home = () => {
|
|||||||
<HomeLogo />
|
<HomeLogo />
|
||||||
<SearchBar />
|
<SearchBar />
|
||||||
<InfoBox />
|
<InfoBox />
|
||||||
<BoardsList multisub={defaultSubplebbits} />
|
<BoardsList multisub={directories} />
|
||||||
<PopularThreadsBox multisub={defaultSubplebbits} subplebbits={subplebbits} />
|
<PopularThreadsBox directories={directories} subplebbits={subplebbits} />
|
||||||
<Stats subplebbitAddresses={subplebbitAddresses} />
|
<Stats directoryAddresses={directoryAddresses} />
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import { getCommentMediaInfo } from '../../../lib/utils/media-utils';
|
|||||||
import { CatalogPostMedia } from '../../../components/catalog-row';
|
import { CatalogPostMedia } from '../../../components/catalog-row';
|
||||||
import LoadingEllipsis from '../../../components/loading-ellipsis';
|
import LoadingEllipsis from '../../../components/loading-ellipsis';
|
||||||
import BoxModal from '../box-modal';
|
import BoxModal from '../box-modal';
|
||||||
import { MultisubSubplebbit, useDefaultSubplebbits } from '../../../hooks/use-default-subplebbits';
|
import { DirectoryCommunity } from '../../../hooks/use-directories';
|
||||||
import { getBoardPath } from '../../../lib/utils/route-utils';
|
import { getBoardPath } from '../../../lib/utils/route-utils';
|
||||||
import { removeMarkdown } from '../../../lib/utils/post-utils';
|
import { removeMarkdown } from '../../../lib/utils/post-utils';
|
||||||
|
|
||||||
interface PopularThreadProps {
|
interface PopularThreadProps {
|
||||||
post: Comment;
|
post: Comment;
|
||||||
multisub: MultisubSubplebbit[];
|
directories: DirectoryCommunity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ContentPreview = ({ content, maxLength = 99 }: { content: string; maxLength?: number }) => {
|
export const ContentPreview = ({ content, maxLength = 99 }: { content: string; maxLength?: number }) => {
|
||||||
@@ -27,15 +27,14 @@ export const ContentPreview = ({ content, maxLength = 99 }: { content: string; m
|
|||||||
|
|
||||||
// Memoize to prevent rerenders when parent rerenders due to updatingState
|
// Memoize to prevent rerenders when parent rerenders due to updatingState
|
||||||
const PopularThreadCard = memo(
|
const PopularThreadCard = memo(
|
||||||
({ post, multisub }: PopularThreadProps) => {
|
({ post, directories }: PopularThreadProps) => {
|
||||||
const { cid, content, link, linkHeight, linkWidth, subplebbitAddress, thumbnailUrl, title } = post || {};
|
const { cid, content, link, linkHeight, linkWidth, subplebbitAddress, thumbnailUrl, title } = post || {};
|
||||||
const commentMediaInfo = getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
const commentMediaInfo = getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
|
||||||
|
|
||||||
// Find the matching MultisubSubplebbit entry and get its title
|
// Find the matching DirectoryCommunity entry and get its title
|
||||||
const multisubEntry = multisub.find((ms) => ms?.address === subplebbitAddress);
|
const directoriesEntry = directories.find((ms) => ms?.address === subplebbitAddress);
|
||||||
const boardTitle = multisubEntry?.title?.replace(/^\/[^/]+\/\s*-\s*/, '') || '';
|
const boardTitle = directoriesEntry?.title?.replace(/^\/[^/]+\/\s*-\s*/, '') || '';
|
||||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.popularThread} key={cid}>
|
<div className={styles.popularThread} key={cid}>
|
||||||
@@ -57,37 +56,37 @@ const PopularThreadCard = memo(
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
// Custom equality: rerender if post.cid or multisub entry title changes
|
// Custom equality: rerender if post.cid or directories entry title changes
|
||||||
(prevProps, nextProps) => {
|
(prevProps, nextProps) => {
|
||||||
if (prevProps.post?.cid !== nextProps.post?.cid) return false;
|
if (prevProps.post?.cid !== nextProps.post?.cid) return false;
|
||||||
// Compare the relevant multisub entry for this post's subplebbitAddress
|
// Compare the relevant directories entry for this post's subplebbitAddress
|
||||||
const prevEntry = prevProps.multisub.find((ms) => ms?.address === prevProps.post?.subplebbitAddress);
|
const prevEntry = prevProps.directories.find((ms) => ms?.address === prevProps.post?.subplebbitAddress);
|
||||||
const nextEntry = nextProps.multisub.find((ms) => ms?.address === nextProps.post?.subplebbitAddress);
|
const nextEntry = nextProps.directories.find((ms) => ms?.address === nextProps.post?.subplebbitAddress);
|
||||||
return prevEntry?.title === nextEntry?.title;
|
return prevEntry?.title === nextEntry?.title;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: MultisubSubplebbit[]; subplebbits: any }) => {
|
const PopularThreadsBox = ({ directories, subplebbits }: { directories: DirectoryCommunity[]; subplebbits: any }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { showWorksafeContentOnly, showNsfwContentOnly } = usePopularThreadsOptionsStore();
|
const { showWorksafeContentOnly, showNsfwContentOnly } = usePopularThreadsOptionsStore();
|
||||||
|
|
||||||
const getFilteredSubplebbits = () => {
|
const getFilteredSubplebbits = () => {
|
||||||
if (showWorksafeContentOnly) {
|
if (showWorksafeContentOnly) {
|
||||||
return subplebbits.filter((sub: Subplebbit) => {
|
return subplebbits.filter((sub: Subplebbit) => {
|
||||||
const multisubEntry = multisub.find((ms) => ms?.address === sub?.address);
|
const directoriesEntry = directories.find((ms) => ms?.address === sub?.address);
|
||||||
return multisubEntry ? !multisubEntry.nsfw : true;
|
return directoriesEntry ? !directoriesEntry.nsfw : true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (showNsfwContentOnly) {
|
if (showNsfwContentOnly) {
|
||||||
return subplebbits.filter((sub: Subplebbit) => {
|
return subplebbits.filter((sub: Subplebbit) => {
|
||||||
const multisubEntry = multisub.find((ms) => ms?.address === sub?.address);
|
const directoriesEntry = directories.find((ms) => ms?.address === sub?.address);
|
||||||
return multisubEntry ? multisubEntry.nsfw : false;
|
return directoriesEntry ? directoriesEntry.nsfw : false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return subplebbits;
|
return subplebbits;
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredSubplebbits = useMemo(getFilteredSubplebbits, [subplebbits, showWorksafeContentOnly, showNsfwContentOnly, multisub]);
|
const filteredSubplebbits = useMemo(getFilteredSubplebbits, [subplebbits, showWorksafeContentOnly, showNsfwContentOnly, directories]);
|
||||||
const { popularPosts } = usePopularPosts(filteredSubplebbits);
|
const { popularPosts } = usePopularPosts(filteredSubplebbits);
|
||||||
const isLoading = popularPosts.length === 0;
|
const isLoading = popularPosts.length === 0;
|
||||||
|
|
||||||
@@ -98,7 +97,11 @@ const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: MultisubSubple
|
|||||||
<BoxModal />
|
<BoxModal />
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles.boxContent} ${styles.popularThreads} ${isLoading ? styles.popularThreadsLoading : ''}`}>
|
<div className={`${styles.boxContent} ${styles.popularThreads} ${isLoading ? styles.popularThreadsLoading : ''}`}>
|
||||||
{isLoading ? <LoadingEllipsis string={t('loading')} /> : popularPosts.map((post: any) => <PopularThreadCard key={post.cid} post={post} multisub={multisub} />)}
|
{isLoading ? (
|
||||||
|
<LoadingEllipsis string={t('loading')} />
|
||||||
|
) : (
|
||||||
|
popularPosts.map((post: any) => <PopularThreadCard key={post.cid} post={post} directories={directories} />)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { useParams, Link } from 'react-router-dom';
|
|||||||
import { useFeed, Comment, usePublishCommentModeration, useEditedComment, useSubplebbit, useComment } from '@plebbit/plebbit-react-hooks';
|
import { useFeed, Comment, usePublishCommentModeration, useEditedComment, useSubplebbit, useComment } from '@plebbit/plebbit-react-hooks';
|
||||||
import useAccountsStore from '@plebbit/plebbit-react-hooks/dist/stores/accounts';
|
import useAccountsStore from '@plebbit/plebbit-react-hooks/dist/stores/accounts';
|
||||||
import { Virtuoso } from 'react-virtuoso';
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
|
||||||
import styles from './mod-queue.module.css';
|
import styles from './mod-queue.module.css';
|
||||||
import useModQueueStore from '../../stores/use-mod-queue-store';
|
import useModQueueStore from '../../stores/use-mod-queue-store';
|
||||||
import { useAccountSubplebbitsWithMetadata } from '../../hooks/use-account-subplebbits-with-metadata';
|
import { useAccountSubplebbitsWithMetadata } from '../../hooks/use-account-subplebbits-with-metadata';
|
||||||
@@ -12,7 +11,7 @@ import LoadingEllipsis from '../../components/loading-ellipsis';
|
|||||||
import ErrorDisplay from '../../components/error-display/error-display';
|
import ErrorDisplay from '../../components/error-display/error-display';
|
||||||
import { useFeedStateString } from '../../hooks/use-state-string';
|
import { useFeedStateString } from '../../hooks/use-state-string';
|
||||||
import { getSubplebbitAddress, getBoardPath } from '../../lib/utils/route-utils';
|
import { getSubplebbitAddress, getBoardPath } from '../../lib/utils/route-utils';
|
||||||
import { useDefaultSubplebbits, MultisubSubplebbit } from '../../hooks/use-default-subplebbits';
|
import { useDirectories, DirectoryCommunity } from '../../hooks/use-directories';
|
||||||
import { useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
|
import { useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
|
||||||
import { getHasThumbnail, getCommentMediaInfo } from '../../lib/utils/media-utils';
|
import { getHasThumbnail, getCommentMediaInfo } from '../../lib/utils/media-utils';
|
||||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||||
@@ -430,10 +429,10 @@ const ModQueueFeedPost = ({ comment }: { comment: Comment }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface ModQueueBoardFilterProps {
|
interface ModQueueBoardFilterProps {
|
||||||
subplebbits: MultisubSubplebbit[];
|
communities: DirectoryCommunity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModQueueBoardFilter = ({ subplebbits }: ModQueueBoardFilterProps) => {
|
const ModQueueBoardFilter = ({ communities }: ModQueueBoardFilterProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { selectedBoardFilter, setSelectedBoardFilter } = useModQueueStore();
|
const { selectedBoardFilter, setSelectedBoardFilter } = useModQueueStore();
|
||||||
|
|
||||||
@@ -442,12 +441,12 @@ const ModQueueBoardFilter = ({ subplebbits }: ModQueueBoardFilterProps) => {
|
|||||||
setSelectedBoardFilter(value);
|
setSelectedBoardFilter(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!subplebbits || subplebbits.length === 0) {
|
if (!communities || communities.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to first board if none selected
|
// Default to first board if none selected
|
||||||
const firstBoardAddress = subplebbits.find((sub) => sub.address)?.address;
|
const firstBoardAddress = communities.find((sub) => sub.address)?.address;
|
||||||
const currentFilter = selectedBoardFilter || firstBoardAddress || '';
|
const currentFilter = selectedBoardFilter || firstBoardAddress || '';
|
||||||
|
|
||||||
// Auto-select first board if none is selected
|
// Auto-select first board if none is selected
|
||||||
@@ -461,12 +460,12 @@ const ModQueueBoardFilter = ({ subplebbits }: ModQueueBoardFilterProps) => {
|
|||||||
<div className={styles.filterContainer}>
|
<div className={styles.filterContainer}>
|
||||||
<label>{t('filter_by_board')}:</label>
|
<label>{t('filter_by_board')}:</label>
|
||||||
<select value={currentFilter} onChange={handleChange}>
|
<select value={currentFilter} onChange={handleChange}>
|
||||||
{subplebbits.map((sub) => {
|
{communities.map((sub) => {
|
||||||
const address = sub.address;
|
const address = sub.address;
|
||||||
if (!address) return null;
|
if (!address) return null;
|
||||||
return (
|
return (
|
||||||
<option key={address} value={address}>
|
<option key={address} value={address}>
|
||||||
/{getBoardPath(address, subplebbits)}/
|
/{getBoardPath(address, communities)}/
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -594,7 +593,7 @@ export const ModQueueButton = ({ boardIdentifier, isMobile }: ModQueueButtonProp
|
|||||||
(state) => {
|
(state) => {
|
||||||
const activeAccountId = state.activeAccountId;
|
const activeAccountId = state.activeAccountId;
|
||||||
const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined;
|
const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined;
|
||||||
const accountSubplebbits = activeAccount?.subplebbits || {};
|
const accountSubplebbits = activeAccount?.communities || {};
|
||||||
return Object.keys(accountSubplebbits);
|
return Object.keys(accountSubplebbits);
|
||||||
},
|
},
|
||||||
(prev, next) => {
|
(prev, next) => {
|
||||||
@@ -603,14 +602,14 @@ export const ModQueueButton = ({ boardIdentifier, isMobile }: ModQueueButtonProp
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const resolvedAddress = useMemo(() => {
|
const resolvedAddress = useMemo(() => {
|
||||||
if (boardIdentifier) {
|
if (boardIdentifier) {
|
||||||
return getSubplebbitAddress(boardIdentifier, defaultSubplebbits);
|
return getSubplebbitAddress(boardIdentifier, directories);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}, [boardIdentifier, defaultSubplebbits]);
|
}, [boardIdentifier, directories]);
|
||||||
|
|
||||||
const subplebbitAddresses = useMemo(() => {
|
const subplebbitAddresses = useMemo(() => {
|
||||||
if (resolvedAddress) {
|
if (resolvedAddress) {
|
||||||
@@ -652,7 +651,7 @@ export const ModQueueView = ({ boardIdentifier: propBoardIdentifier }: ModQueueV
|
|||||||
(state) => {
|
(state) => {
|
||||||
const activeAccountId = state.activeAccountId;
|
const activeAccountId = state.activeAccountId;
|
||||||
const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined;
|
const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined;
|
||||||
const accountSubplebbits = activeAccount?.subplebbits || {};
|
const accountSubplebbits = activeAccount?.communities || {};
|
||||||
return Object.keys(accountSubplebbits);
|
return Object.keys(accountSubplebbits);
|
||||||
},
|
},
|
||||||
(prev, next) => {
|
(prev, next) => {
|
||||||
@@ -661,18 +660,18 @@ export const ModQueueView = ({ boardIdentifier: propBoardIdentifier }: ModQueueV
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
const boardIdentifier = propBoardIdentifier || params.boardIdentifier;
|
const boardIdentifier = propBoardIdentifier || params.boardIdentifier;
|
||||||
|
|
||||||
const resolvedAddress = useMemo(() => {
|
const resolvedAddress = useMemo(() => {
|
||||||
if (boardIdentifier) {
|
if (boardIdentifier) {
|
||||||
return getSubplebbitAddress(boardIdentifier, defaultSubplebbits);
|
return getSubplebbitAddress(boardIdentifier, directories);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}, [boardIdentifier, defaultSubplebbits]);
|
}, [boardIdentifier, directories]);
|
||||||
|
|
||||||
const subplebbitsWithMetadata = useAccountSubplebbitsWithMetadata();
|
const communitiesWithMetadata = useAccountSubplebbitsWithMetadata();
|
||||||
|
|
||||||
const subplebbitAddresses = useMemo(() => {
|
const subplebbitAddresses = useMemo(() => {
|
||||||
if (resolvedAddress) {
|
if (resolvedAddress) {
|
||||||
@@ -740,7 +739,7 @@ export const ModQueueView = ({ boardIdentifier: propBoardIdentifier }: ModQueueV
|
|||||||
{!resolvedAddress && (
|
{!resolvedAddress && (
|
||||||
<div className={styles.controls}>
|
<div className={styles.controls}>
|
||||||
<div className={styles.controlsLeft}>
|
<div className={styles.controlsLeft}>
|
||||||
<ModQueueBoardFilter subplebbits={subplebbitsWithMetadata} />
|
<ModQueueBoardFilter communities={communitiesWithMetadata} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
import { useSubplebbitField } from '../../hooks/use-stable-subplebbit';
|
import { useSubplebbitField } from '../../hooks/use-stable-subplebbit';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { getSubplebbitAddress } from '../../lib/utils/route-utils';
|
import { getSubplebbitAddress } from '../../lib/utils/route-utils';
|
||||||
import { HomeLogo } from '../home';
|
import { HomeLogo } from '../home';
|
||||||
import styles from './not-found.module.css';
|
import styles from './not-found.module.css';
|
||||||
@@ -18,8 +18,8 @@ const NotFound = () => {
|
|||||||
// Extract boardIdentifier from pathname (could be directory code or address)
|
// Extract boardIdentifier from pathname (could be directory code or address)
|
||||||
const pathParts = location.pathname.split('/').filter(Boolean);
|
const pathParts = location.pathname.split('/').filter(Boolean);
|
||||||
const boardIdentifier = pathParts[0] && pathParts[0] !== 'not-found' && pathParts[0] !== 'faq' ? pathParts[0] : '';
|
const boardIdentifier = pathParts[0] && pathParts[0] !== 'not-found' && pathParts[0] !== 'faq' ? pathParts[0] : '';
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const subplebbitAddress = boardIdentifier ? getSubplebbitAddress(boardIdentifier, defaultSubplebbits) : '';
|
const subplebbitAddress = boardIdentifier ? getSubplebbitAddress(boardIdentifier, directories) : '';
|
||||||
// Only subscribe to address and shortAddress to avoid rerenders from updatingState changes
|
// Only subscribe to address and shortAddress to avoid rerenders from updatingState changes
|
||||||
const address = useSubplebbitField(subplebbitAddress, (subplebbit) => subplebbit?.address);
|
const address = useSubplebbitField(subplebbitAddress, (subplebbit) => subplebbit?.address);
|
||||||
const shortAddress = useSubplebbitField(subplebbitAddress, (subplebbit) => subplebbit?.shortAddress);
|
const shortAddress = useSubplebbitField(subplebbitAddress, (subplebbit) => subplebbit?.shortAddress);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useAccountComment, useAccountComments } from '@plebbit/plebbit-react-hooks';
|
import { useAccountComment, useAccountComments } from '@plebbit/plebbit-react-hooks';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||||
import { Post } from '../post';
|
import { Post } from '../post';
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ const PendingPost = () => {
|
|||||||
const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined;
|
const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined;
|
||||||
const post = useAccountComment({ commentIndex });
|
const post = useAccountComment({ commentIndex });
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
useEffect(() => window.scrollTo(0, 0), []);
|
useEffect(() => window.scrollTo(0, 0), []);
|
||||||
|
|
||||||
@@ -31,10 +31,10 @@ const PendingPost = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (post?.cid && post?.subplebbitAddress) {
|
if (post?.cid && post?.subplebbitAddress) {
|
||||||
const boardPath = getBoardPath(post.subplebbitAddress, defaultSubplebbits);
|
const boardPath = getBoardPath(post.subplebbitAddress, directories);
|
||||||
navigate(`/${boardPath}/thread/${post.cid}`, { replace: true });
|
navigate(`/${boardPath}/thread/${post.cid}`, { replace: true });
|
||||||
}
|
}
|
||||||
}, [post, navigate, defaultSubplebbits]);
|
}, [post, navigate, directories]);
|
||||||
|
|
||||||
return <Post post={post} />;
|
return <Post post={post} />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useSubplebbitField } from '../../hooks/use-stable-subplebbit';
|
|||||||
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||||
import { isAllView } from '../../lib/utils/view-utils';
|
import { isAllView } from '../../lib/utils/view-utils';
|
||||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
import { useDirectories } from '../../hooks/use-directories';
|
||||||
import { isDirectoryBoard } from '../../lib/utils/route-utils';
|
import { isDirectoryBoard } from '../../lib/utils/route-utils';
|
||||||
import useIsMobile from '../../hooks/use-is-mobile';
|
import useIsMobile from '../../hooks/use-is-mobile';
|
||||||
import ErrorDisplay from '../../components/error-display/error-display';
|
import ErrorDisplay from '../../components/error-display/error-display';
|
||||||
@@ -113,7 +113,7 @@ const PostPage = () => {
|
|||||||
|
|
||||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||||
const { error: subplebbitError, shortAddress, title } = subplebbit || {};
|
const { error: subplebbitError, shortAddress, title } = subplebbit || {};
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
|
|
||||||
// if the comment is a reply, return the post comment instead, then the reply will be highlighted in the thread
|
// if the comment is a reply, return the post comment instead, then the reply will be highlighted in the thread
|
||||||
const postComment = useComment({ commentCid: comment?.postCid });
|
const postComment = useComment({ commentCid: comment?.postCid });
|
||||||
@@ -133,7 +133,7 @@ const PostPage = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const boardIdentifier = params.boardIdentifier;
|
const boardIdentifier = params.boardIdentifier;
|
||||||
const isDirectory = boardIdentifier ? isDirectoryBoard(boardIdentifier, defaultSubplebbits) : false;
|
const isDirectory = boardIdentifier ? isDirectoryBoard(boardIdentifier, directories) : false;
|
||||||
|
|
||||||
let boardTitle: string;
|
let boardTitle: string;
|
||||||
if (isInAllView) {
|
if (isInAllView) {
|
||||||
@@ -147,7 +147,7 @@ const PostPage = () => {
|
|||||||
const postTitle = post?.title?.slice(0, 30) || post?.content?.slice(0, 30);
|
const postTitle = post?.title?.slice(0, 30) || post?.content?.slice(0, 30);
|
||||||
const postTitlePart = postTitle ? ` - ${postTitle.trim()}...` : '';
|
const postTitlePart = postTitle ? ` - ${postTitle.trim()}...` : '';
|
||||||
document.title = `${boardTitle}${postTitlePart} - 5chan`;
|
document.title = `${boardTitle}${postTitlePart} - 5chan`;
|
||||||
}, [title, shortAddress, subplebbitAddress, post?.title, post?.content, isInAllView, t, params.boardIdentifier, defaultSubplebbits]);
|
}, [title, shortAddress, subplebbitAddress, post?.title, post?.content, isInAllView, t, params.boardIdentifier, directories]);
|
||||||
|
|
||||||
const shouldShowCommentError = comment?.error?.message && !comment?.cid;
|
const shouldShowCommentError = comment?.error?.message && !comment?.cid;
|
||||||
const shouldShowPostError = post?.error && post?.replyCount > 0 && post?.replies?.length === 0;
|
const shouldShowPostError = post?.error && post?.replyCount > 0 && post?.replies?.length === 0;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useState, FormEvent } from 'react';
|
import { useEffect, useState, FormEvent } from 'react';
|
||||||
import { useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
import { useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||||
import { Footer, HomeLogo } from '../home';
|
import { Footer, HomeLogo } from '../home';
|
||||||
import { useDefaultSubplebbits, MultisubSubplebbit } from '../../hooks/use-default-subplebbits';
|
import { useDirectories, DirectoryCommunity } from '../../hooks/use-directories';
|
||||||
import styles from './rules.module.css';
|
import styles from './rules.module.css';
|
||||||
|
|
||||||
const getBoardShortCode = (title?: string): string => {
|
const getBoardShortCode = (title?: string): string => {
|
||||||
@@ -16,7 +16,7 @@ const getBoardName = (title?: string): string => {
|
|||||||
return match ? match[1] : title;
|
return match ? match[1] : title;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BoardRulesDisplay = ({ subplebbitAddress, defaultSubplebbits }: { subplebbitAddress: string; defaultSubplebbits: MultisubSubplebbit[] }) => {
|
const BoardRulesDisplay = ({ subplebbitAddress, directories }: { subplebbitAddress: string; directories: DirectoryCommunity[] }) => {
|
||||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||||
const { rules, state, title, shortAddress } = subplebbit || {};
|
const { rules, state, title, shortAddress } = subplebbit || {};
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ const BoardRulesDisplay = ({ subplebbitAddress, defaultSubplebbits }: { subplebb
|
|||||||
|
|
||||||
const isLoaded = state === 'succeeded';
|
const isLoaded = state === 'succeeded';
|
||||||
|
|
||||||
const defaultSub = defaultSubplebbits.find((sub) => sub.address === subplebbitAddress);
|
const defaultSub = directories.find((sub) => sub.address === subplebbitAddress);
|
||||||
let displayTitle: string;
|
let displayTitle: string;
|
||||||
if (defaultSub?.title) {
|
if (defaultSub?.title) {
|
||||||
const shortCode = getBoardShortCode(defaultSub.title);
|
const shortCode = getBoardShortCode(defaultSub.title);
|
||||||
@@ -87,11 +87,11 @@ const BoardRulesDisplay = ({ subplebbitAddress, defaultSubplebbits }: { subplebb
|
|||||||
};
|
};
|
||||||
|
|
||||||
const BoardSelector = ({
|
const BoardSelector = ({
|
||||||
defaultSubplebbits,
|
directories,
|
||||||
selectedAddress,
|
selectedAddress,
|
||||||
onSelect,
|
onSelect,
|
||||||
}: {
|
}: {
|
||||||
defaultSubplebbits: MultisubSubplebbit[];
|
directories: DirectoryCommunity[];
|
||||||
selectedAddress: string;
|
selectedAddress: string;
|
||||||
onSelect: (address: string) => void;
|
onSelect: (address: string) => void;
|
||||||
}) => {
|
}) => {
|
||||||
@@ -121,7 +121,7 @@ const BoardSelector = ({
|
|||||||
<div className={styles.selectorRow}>
|
<div className={styles.selectorRow}>
|
||||||
<select value={selectedAddress} onChange={handleSelectChange} className={styles.boardSelect}>
|
<select value={selectedAddress} onChange={handleSelectChange} className={styles.boardSelect}>
|
||||||
<option value=''>Select board...</option>
|
<option value=''>Select board...</option>
|
||||||
{defaultSubplebbits.map((sub) => {
|
{directories.map((sub) => {
|
||||||
const shortCode = getBoardShortCode(sub.title);
|
const shortCode = getBoardShortCode(sub.title);
|
||||||
const boardName = getBoardName(sub.title);
|
const boardName = getBoardName(sub.title);
|
||||||
return (
|
return (
|
||||||
@@ -151,7 +151,7 @@ const BoardSelector = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Rules = () => {
|
const Rules = () => {
|
||||||
const defaultSubplebbits = useDefaultSubplebbits();
|
const directories = useDirectories();
|
||||||
const [selectedAddress, setSelectedAddress] = useState('');
|
const [selectedAddress, setSelectedAddress] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -175,8 +175,8 @@ const Rules = () => {
|
|||||||
Please read and respect the rules of whatever board you decide to post to.
|
Please read and respect the rules of whatever board you decide to post to.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<BoardSelector defaultSubplebbits={defaultSubplebbits} selectedAddress={selectedAddress} onSelect={setSelectedAddress} />
|
<BoardSelector directories={directories} selectedAddress={selectedAddress} onSelect={setSelectedAddress} />
|
||||||
{selectedAddress && <BoardRulesDisplay subplebbitAddress={selectedAddress} defaultSubplebbits={defaultSubplebbits} />}
|
{selectedAddress && <BoardRulesDisplay subplebbitAddress={selectedAddress} directories={directories} />}
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user