mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
perf(bundle): replace plebbit-js imports with local utility, split chunks, fix CLS and rerenders
Eliminate direct @plebbit/plebbit-js (8.7MB) imports from all UI components by replacing Plebbit.getShortAddress() with a local get-short-address utility. Add Vite manual chunks for plebbit-js, plebbit-react-hooks, and react-spring/use-gesture. Fix catalog CLS by matching skeleton to wrapper dimensions. Lazy-load ChallengeModal and ReplyModal. Add failed-URL cache to useFetchGifFirstFrame, optimize useHide selector, and memoize useFeed options in mod-queue.
This commit is contained in:
+17
-13
@@ -27,9 +27,7 @@ import PendingPost from './views/pending-post';
|
|||||||
import Post from './views/post';
|
import Post from './views/post';
|
||||||
import Rules from './views/rules';
|
import Rules from './views/rules';
|
||||||
import BoardHeader from './components/board-header';
|
import BoardHeader from './components/board-header';
|
||||||
import ChallengeModal from './components/challenge-modal';
|
|
||||||
import FeedCacheContainer from './components/feed-cache-container';
|
import FeedCacheContainer from './components/feed-cache-container';
|
||||||
import ReplyModal from './components/reply-modal';
|
|
||||||
import PostForm from './components/post-form';
|
import PostForm from './components/post-form';
|
||||||
import BoardBlotter from './components/board-blotter';
|
import BoardBlotter from './components/board-blotter';
|
||||||
import BoardsBar from './components/boardsbar';
|
import BoardsBar from './components/boardsbar';
|
||||||
@@ -37,8 +35,10 @@ import BoardsBar from './components/boardsbar';
|
|||||||
const AccountDataEditor = lazy(() => import('./views/account-data-editor'));
|
const AccountDataEditor = lazy(() => import('./views/account-data-editor'));
|
||||||
const BoardsBarEditModal = lazy(() => import('./components/boardsbar-edit-modal'));
|
const BoardsBarEditModal = lazy(() => import('./components/boardsbar-edit-modal'));
|
||||||
const CreateBoardModal = lazy(() => import('./components/create-board-modal'));
|
const CreateBoardModal = lazy(() => import('./components/create-board-modal'));
|
||||||
|
const ChallengeModal = lazy(() => import('./components/challenge-modal'));
|
||||||
const DirectoryModal = lazy(() => import('./components/directory-modal'));
|
const DirectoryModal = lazy(() => import('./components/directory-modal'));
|
||||||
const DisclaimerModal = lazy(() => import('./components/disclaimer-modal'));
|
const DisclaimerModal = lazy(() => import('./components/disclaimer-modal'));
|
||||||
|
const ReplyModal = lazy(() => import('./components/reply-modal'));
|
||||||
const SettingsModal = lazy(() => import('./components/settings-modal'));
|
const SettingsModal = lazy(() => import('./components/settings-modal'));
|
||||||
|
|
||||||
// Preload all theme assets (buttons, backgrounds) immediately on app load
|
// Preload all theme assets (buttons, backgrounds) immediately on app load
|
||||||
@@ -134,18 +134,22 @@ const GlobalLayout = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ChallengeModal />
|
<Suspense fallback={null}>
|
||||||
|
<ChallengeModal />
|
||||||
|
</Suspense>
|
||||||
{activeCid && threadCid && subplebbitAddress && (
|
{activeCid && threadCid && subplebbitAddress && (
|
||||||
<ReplyModal
|
<Suspense fallback={null}>
|
||||||
closeModal={closeModal}
|
<ReplyModal
|
||||||
parentCid={activeCid}
|
closeModal={closeModal}
|
||||||
parentNumber={parentNumber}
|
parentCid={activeCid}
|
||||||
threadNumber={threadNumber}
|
parentNumber={parentNumber}
|
||||||
postCid={threadCid}
|
threadNumber={threadNumber}
|
||||||
scrollY={scrollY}
|
postCid={threadCid}
|
||||||
showReplyModal={showReplyModal}
|
scrollY={scrollY}
|
||||||
subplebbitAddress={subplebbitAddress}
|
showReplyModal={showReplyModal}
|
||||||
/>
|
subplebbitAddress={subplebbitAddress}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
)}
|
)}
|
||||||
{isInSettingsView && (
|
{isInSettingsView && (
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useLocation, useParams, useNavigate } from 'react-router-dom';
|
|||||||
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 useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
|
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
|
||||||
import Plebbit from '@plebbit/plebbit-js';
|
import getShortAddress from '../../lib/get-short-address';
|
||||||
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';
|
||||||
@@ -95,7 +95,7 @@ const BoardHeader = () => {
|
|||||||
? shortAddress.endsWith('.eth') || shortAddress.endsWith('.sol')
|
? shortAddress.endsWith('.eth') || shortAddress.endsWith('.sol')
|
||||||
? shortAddress.slice(0, -4)
|
? shortAddress.slice(0, -4)
|
||||||
: shortAddress
|
: shortAddress
|
||||||
: subplebbitAddress && Plebbit.getShortAddress({ address: subplebbitAddress }))}
|
: subplebbitAddress && getShortAddress(subplebbitAddress))}
|
||||||
{!isInAllView && !isInSubscriptionsView && !isInModView && <OfflineIndicator subplebbitAddress={subplebbitAddress} />}
|
{!isInAllView && !isInSubscriptionsView && !isInModView && <OfflineIndicator subplebbitAddress={subplebbitAddress} />}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.boardSubtitle}>
|
<div className={styles.boardSubtitle}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Plebbit from '@plebbit/plebbit-js';
|
import getShortAddress from '../../lib/get-short-address';
|
||||||
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';
|
||||||
@@ -200,7 +200,7 @@ const BoardsBarDesktop = () => {
|
|||||||
// 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, directories);
|
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 : getShortAddress(address);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span key={address}>
|
<span key={address}>
|
||||||
|
|||||||
@@ -110,8 +110,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.loadingSkeleton {
|
.loadingSkeleton {
|
||||||
width: var(--maxWidth);
|
width: 100%;
|
||||||
height: var(--maxHeight);
|
height: 100%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||||
import { useFloating, offset, size, Placement } from '@floating-ui/react';
|
import { useFloating, offset, size, Placement } from '@floating-ui/react';
|
||||||
import { Comment, useReplies } from '@plebbit/plebbit-react-hooks';
|
import { Comment, useReplies } from '@plebbit/plebbit-react-hooks';
|
||||||
import Plebbit from '@plebbit/plebbit-js';
|
import getShortAddress from '../../lib/get-short-address';
|
||||||
import { shouldShowSnow } from '../../lib/snow';
|
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';
|
||||||
@@ -57,8 +57,8 @@ export const CatalogPostMedia = ({ cid, commentMediaInfo, linkWidth, linkHeight
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'audio') {
|
if (type === 'audio') {
|
||||||
displayWidth = 'unset';
|
displayWidth = `${maxThumbnailSize}px`;
|
||||||
displayHeight = 'unset';
|
displayHeight = '54px';
|
||||||
}
|
}
|
||||||
|
|
||||||
const numericWidth = parseInt(displayWidth) || undefined;
|
const numericWidth = parseInt(displayWidth) || undefined;
|
||||||
@@ -288,7 +288,7 @@ const CatalogPost = memo(
|
|||||||
{author?.displayName || capitalize(t('anonymous'))}
|
{author?.displayName || capitalize(t('anonymous'))}
|
||||||
{isCatalogPostAuthorMod && <span className='capitalize'>{` ## Board ${catalogPostAuthorRole}`}</span>}
|
{isCatalogPostAuthorMod && <span className='capitalize'>{` ## Board ${catalogPostAuthorRole}`}</span>}
|
||||||
</span>
|
</span>
|
||||||
{(isInAllView || isInSubscriptionsView) && subplebbitAddress && ` to p/${Plebbit.getShortAddress({ address: subplebbitAddress })}`}
|
{(isInAllView || isInSubscriptionsView) && subplebbitAddress && ` to p/${getShortAddress(subplebbitAddress)}`}
|
||||||
<span className={styles.postAgo}> {getFormattedTimeAgo(timestamp)}</span>
|
<span className={styles.postAgo}> {getFormattedTimeAgo(timestamp)}</span>
|
||||||
{replyCount > 0 && (
|
{replyCount > 0 && (
|
||||||
<div className={styles.postLast}>
|
<div className={styles.postLast}>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Trans, useTranslation } from 'react-i18next';
|
|||||||
import { Comment, useComment } from '@plebbit/plebbit-react-hooks';
|
import { Comment, useComment } 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 usePostNumberStore from '../../stores/use-post-number-store';
|
import usePostNumberStore from '../../stores/use-post-number-store';
|
||||||
import Plebbit from '@plebbit/plebbit-js';
|
import getShortAddress from '../../lib/get-short-address';
|
||||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||||
import { isPostPageView } from '../../lib/utils/view-utils';
|
import { isPostPageView } from '../../lib/utils/view-utils';
|
||||||
import useIsMobile from '../../hooks/use-is-mobile';
|
import useIsMobile from '../../hooks/use-is-mobile';
|
||||||
@@ -253,7 +253,7 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => {
|
|||||||
<br />
|
<br />
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={`${t('ban_expires_at', {
|
content={`${t('ban_expires_at', {
|
||||||
address: subplebbitAddress && Plebbit.getShortAddress({ address: subplebbitAddress }),
|
address: subplebbitAddress && getShortAddress(subplebbitAddress),
|
||||||
timestamp: getFormattedDate(post?.author?.subplebbit?.banExpiresAt),
|
timestamp: getFormattedDate(post?.author?.subplebbit?.banExpiresAt),
|
||||||
interpolation: { escapeValue: false },
|
interpolation: { escapeValue: false },
|
||||||
})}${reason ? `. ${capitalize(t('reason'))}: "${reason}"` : ''}`}
|
})}${reason ? `. ${capitalize(t('reason'))}: "${reason}"` : ''}`}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Trans, useTranslation } from 'react-i18next';
|
|||||||
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
|
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
|
||||||
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
||||||
import { Comment, useEditedComment, useReplies, useAccount, useAccountComment } from '@plebbit/plebbit-react-hooks';
|
import { Comment, useEditedComment, useReplies, useAccount, useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||||
import Plebbit from '@plebbit/plebbit-js';
|
import getShortAddress from '../../lib/get-short-address';
|
||||||
import styles from '../../views/post/post.module.css';
|
import styles from '../../views/post/post.module.css';
|
||||||
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
|
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
|
||||||
import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/post-utils';
|
import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/post-utils';
|
||||||
@@ -211,7 +211,7 @@ const PostInfo = ({
|
|||||||
const alertThresholdSeconds = getAlertThresholdSeconds();
|
const alertThresholdSeconds = getAlertThresholdSeconds();
|
||||||
const isOverThreshold = isAwaitingApproval && timeWaiting > alertThresholdSeconds;
|
const isOverThreshold = isAwaitingApproval && timeWaiting > alertThresholdSeconds;
|
||||||
|
|
||||||
const userID = address && Plebbit.getShortAddress({ address }); // shortened to 8 chars for display; users can verify the full user ID via "Copy user ID" in the post menu to guard against spoofing
|
const userID = address && getShortAddress(address); // shortened to 8 chars for display; users can verify the full user ID via "Copy user ID" in the post menu to guard against spoofing
|
||||||
const userIDBackgroundColor = hashStringToColor(userID);
|
const userIDBackgroundColor = hashStringToColor(userID);
|
||||||
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
|
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
|
||||||
|
|
||||||
@@ -562,7 +562,7 @@ const PostMedia = ({
|
|||||||
? boardPath
|
? boardPath
|
||||||
: subplebbitAddress.endsWith('.eth') || subplebbitAddress.endsWith('.sol')
|
: subplebbitAddress.endsWith('.eth') || subplebbitAddress.endsWith('.sol')
|
||||||
? subplebbitAddress
|
? subplebbitAddress
|
||||||
: Plebbit.getShortAddress({ address: subplebbitAddress });
|
: getShortAddress(subplebbitAddress);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.file}>
|
<div className={styles.file}>
|
||||||
@@ -741,7 +741,7 @@ const PostDesktop = ({
|
|||||||
? boardPath
|
? boardPath
|
||||||
: subplebbitAddress.endsWith('.eth') || subplebbitAddress.endsWith('.sol')
|
: subplebbitAddress.endsWith('.eth') || subplebbitAddress.endsWith('.sol')
|
||||||
? subplebbitAddress
|
? subplebbitAddress
|
||||||
: Plebbit.getShortAddress({ address: subplebbitAddress })
|
: getShortAddress(subplebbitAddress)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const { hidden, unhide, hide } = useHide({ cid });
|
const { hidden, unhide, hide } = useHide({ cid });
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||||
import { Comment, setAccount, useAccount, useAccountComment, useAccountSubplebbits, useEditedComment } from '@plebbit/plebbit-react-hooks';
|
import { Comment, setAccount, useAccount, useAccountComment, useAccountSubplebbits, useEditedComment } from '@plebbit/plebbit-react-hooks';
|
||||||
import Plebbit from '@plebbit/plebbit-js';
|
import getShortAddress from '../../lib/get-short-address';
|
||||||
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
|
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
|
||||||
import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages';
|
import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages';
|
||||||
import { getHasThumbnail, getLinkMediaInfo } from '../../lib/utils/media-utils';
|
import { getHasThumbnail, getLinkMediaInfo } from '../../lib/utils/media-utils';
|
||||||
@@ -280,7 +280,7 @@ const PostFormFields = ({
|
|||||||
{isInModView &&
|
{isInModView &&
|
||||||
accountSubplebbitAddresses.map((address: string) => (
|
accountSubplebbitAddresses.map((address: string) => (
|
||||||
<option key={address} value={address}>
|
<option key={address} value={address}>
|
||||||
{address && Plebbit.getShortAddress({ address })}
|
{address && getShortAddress(address)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
{isInSubscriptionsView &&
|
{isInSubscriptionsView &&
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
|
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
|
||||||
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
||||||
import { Comment, useEditedComment, useReplies, useAccount, usePublishCommentModeration, useAccountComment } from '@plebbit/plebbit-react-hooks';
|
import { Comment, useEditedComment, useReplies, useAccount, usePublishCommentModeration, useAccountComment } from '@plebbit/plebbit-react-hooks';
|
||||||
import Plebbit from '@plebbit/plebbit-js';
|
import getShortAddress from '../../lib/get-short-address';
|
||||||
import styles from '../../views/post/post.module.css';
|
import styles from '../../views/post/post.module.css';
|
||||||
import { shouldShowSnow } from '../../lib/snow';
|
import { shouldShowSnow } from '../../lib/snow';
|
||||||
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
||||||
@@ -66,7 +66,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
|
|||||||
? boardPath
|
? boardPath
|
||||||
: subplebbitAddress.endsWith('.eth') || subplebbitAddress.endsWith('.sol')
|
: subplebbitAddress.endsWith('.eth') || subplebbitAddress.endsWith('.sol')
|
||||||
? subplebbitAddress
|
? subplebbitAddress
|
||||||
: Plebbit.getShortAddress({ address: subplebbitAddress })
|
: getShortAddress(subplebbitAddress)
|
||||||
: undefined;
|
: undefined;
|
||||||
const isReply = parentCid;
|
const isReply = parentCid;
|
||||||
const title = post?.title?.trim();
|
const title = post?.title?.trim();
|
||||||
@@ -203,7 +203,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
|
|||||||
return Math.max(domCount, 1);
|
return Math.max(domCount, 1);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const userID = address && Plebbit.getShortAddress({ address }); // shortened to 8 chars for display; users can verify the full user ID via "Copy user ID" in the post menu to guard against spoofing
|
const userID = address && getShortAddress(address); // shortened to 8 chars for display; users can verify the full user ID via "Copy user ID" in the post menu to guard against spoofing
|
||||||
const userIDBackgroundColor = hashStringToColor(userID);
|
const userIDBackgroundColor = hashStringToColor(userID);
|
||||||
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
|
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { setAccount, useAccount, useSubscribe } from '@plebbit/plebbit-react-hooks';
|
import { setAccount, useAccount, useSubscribe } from '@plebbit/plebbit-react-hooks';
|
||||||
import Plebbit from '@plebbit/plebbit-js';
|
import getShortAddress from '../../../lib/get-short-address';
|
||||||
import styles from './subscriptions-setting.module.css';
|
import styles from './subscriptions-setting.module.css';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -79,7 +79,7 @@ const SubscriptionsSetting = () => {
|
|||||||
<ul className={styles.subscriptions}>
|
<ul className={styles.subscriptions}>
|
||||||
{subscriptions?.map((address: string) => (
|
{subscriptions?.map((address: string) => (
|
||||||
<li key={address} className={styles.subscription}>
|
<li key={address} className={styles.subscription}>
|
||||||
{address && Plebbit.getShortAddress({ address })} <SubscriptionButton address={address} />
|
{address && getShortAddress(address)} <SubscriptionButton address={address} />
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import localForageLru from '@plebbit/plebbit-react-hooks/dist/lib/localforage-lru/index.js';
|
import localForageLru from '@plebbit/plebbit-react-hooks/dist/lib/localforage-lru/index.js';
|
||||||
|
|
||||||
const gifFrameDb = localForageLru.createInstance({ name: '5chanGifFrames', size: 500 });
|
const gifFrameDb = localForageLru.createInstance({ name: '5chanGifFrames', size: 500 });
|
||||||
|
const failedUrls = new Set<string>();
|
||||||
|
|
||||||
const getCachedGifFrame = async (url: string): Promise<string | null> => {
|
const getCachedGifFrame = async (url: string): Promise<string | null> => {
|
||||||
return await gifFrameDb.getItem(url);
|
return await gifFrameDb.getItem(url);
|
||||||
@@ -72,6 +73,10 @@ const useFetchGifFirstFrame = (url: string | undefined) => {
|
|||||||
let isActive = true;
|
let isActive = true;
|
||||||
|
|
||||||
const fetchFrame = async () => {
|
const fetchFrame = async () => {
|
||||||
|
if (failedUrls.has(url)) {
|
||||||
|
if (isActive) setFrameUrl(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const cachedFrame = await getCachedGifFrame(url);
|
const cachedFrame = await getCachedGifFrame(url);
|
||||||
if (cachedFrame) {
|
if (cachedFrame) {
|
||||||
@@ -91,6 +96,7 @@ const useFetchGifFirstFrame = (url: string | undefined) => {
|
|||||||
await setCachedGifFrame(url, objectUrl);
|
await setCachedGifFrame(url, objectUrl);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
failedUrls.add(url);
|
||||||
console.error('Failed to load GIF frame:', error);
|
console.error('Failed to load GIF frame:', error);
|
||||||
if (isActive) setFrameUrl(null);
|
if (isActive) setFrameUrl(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import localForageLru from '@plebbit/plebbit-react-hooks/dist/lib/localforage-lru/index.js';
|
import localForageLru from '@plebbit/plebbit-react-hooks/dist/lib/localforage-lru/index.js';
|
||||||
|
|
||||||
@@ -46,16 +46,14 @@ const initializeHideStore = async () => {
|
|||||||
initializeHideStore();
|
initializeHideStore();
|
||||||
|
|
||||||
const useHide = ({ cid }: { cid: string }) => {
|
const useHide = ({ cid }: { cid: string }) => {
|
||||||
const hiddenCids = useHideStore((state) => state.hiddenCids);
|
const hidden = useHideStore((state) => !!state.hiddenCids[cid]);
|
||||||
const hide = useHideStore((state) => state.hide);
|
const hide = useHideStore((state) => state.hide);
|
||||||
const unhide = useHideStore((state) => state.unhide);
|
const unhide = useHideStore((state) => state.unhide);
|
||||||
|
|
||||||
const hidden = !!hiddenCids[cid];
|
|
||||||
|
|
||||||
const hideCallback = useCallback(() => hide(cid), [hide, cid]);
|
const hideCallback = useCallback(() => hide(cid), [hide, cid]);
|
||||||
const unhideCallback = useCallback(() => unhide(cid), [unhide, cid]);
|
const unhideCallback = useCallback(() => unhide(cid), [unhide, cid]);
|
||||||
|
|
||||||
return { hidden, hide: hideCallback, unhide: unhideCallback };
|
return useMemo(() => ({ hidden, hide: hideCallback, unhide: unhideCallback }), [hidden, hideCallback, unhideCallback]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useHide;
|
export default useHide;
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const getShortAddress = (address: string): string => {
|
||||||
|
if (!address) return '';
|
||||||
|
if (address.includes('.')) return address;
|
||||||
|
if (address.length < 20) return '';
|
||||||
|
return address.slice(8, 20);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getShortAddress;
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
if (import.meta.env.DEV) {
|
if (import.meta.env.DEV) {
|
||||||
const { scan, getReport } = await import('react-scan');
|
import('react-scan').then(({ scan, getReport }) => {
|
||||||
scan({
|
scan({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
showToolbar: !(window as any).__PROFILING__,
|
showToolbar: !(window as any).__PROFILING__,
|
||||||
playSound: !(window as any).__PROFILING__,
|
});
|
||||||
report: true,
|
(window as any).__getReactScanReport = getReport;
|
||||||
});
|
});
|
||||||
(window as any).__getReactScanReport = getReport;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -622,12 +622,17 @@ export const ModQueueButton = ({ boardIdentifier, isMobile }: ModQueueButtonProp
|
|||||||
// Only fetch if we have addresses to check and permissions
|
// Only fetch if we have addresses to check and permissions
|
||||||
const shouldFetch = subplebbitAddresses.length > 0 && isModOfBoard;
|
const shouldFetch = subplebbitAddresses.length > 0 && isModOfBoard;
|
||||||
|
|
||||||
const { feed } = useFeed({
|
const feedAddresses = shouldFetch ? subplebbitAddresses : [];
|
||||||
subplebbitAddresses: shouldFetch ? subplebbitAddresses : [],
|
const feedOptions = useMemo(
|
||||||
modQueue: ['pendingApproval'],
|
() => ({
|
||||||
sortType: 'new',
|
subplebbitAddresses: feedAddresses,
|
||||||
postsPerPage: 200, // Fetch more items to get accurate pending count for the badge
|
modQueue: ['pendingApproval'],
|
||||||
});
|
sortType: 'new' as const,
|
||||||
|
postsPerPage: 200,
|
||||||
|
}),
|
||||||
|
[feedAddresses],
|
||||||
|
);
|
||||||
|
const { feed } = useFeed(feedOptions);
|
||||||
|
|
||||||
if (!shouldFetch || subplebbitAddresses.length === 0) {
|
if (!shouldFetch || subplebbitAddresses.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
@@ -694,11 +699,15 @@ const ModQueueView = ({ boardIdentifier: propBoardIdentifier }: ModQueueViewProp
|
|||||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||||
const { error: subplebbitError } = subplebbit || {};
|
const { error: subplebbitError } = subplebbit || {};
|
||||||
|
|
||||||
const { feed, hasMore, loadMore, reset } = useFeed({
|
const feedOptions = useMemo(
|
||||||
subplebbitAddresses,
|
() => ({
|
||||||
modQueue: ['pendingApproval'],
|
subplebbitAddresses,
|
||||||
postsPerPage: 50,
|
modQueue: ['pendingApproval'],
|
||||||
});
|
postsPerPage: 50,
|
||||||
|
}),
|
||||||
|
[subplebbitAddresses],
|
||||||
|
);
|
||||||
|
const { feed, hasMore, loadMore, reset } = useFeed(feedOptions);
|
||||||
|
|
||||||
const setResetFunction = useFeedResetStore((state) => state.setResetFunction);
|
const setResetFunction = useFeedResetStore((state) => state.setResetFunction);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -169,6 +169,15 @@ export default defineConfig({
|
|||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
manualChunks(id) {
|
manualChunks(id) {
|
||||||
|
if (/[\\/]node_modules[\\/](@plebbit[\\/]plebbit-js)[\\/]/.test(id)) {
|
||||||
|
return 'plebbit-js';
|
||||||
|
}
|
||||||
|
if (/[\\/]node_modules[\\/](@plebbit[\\/]plebbit-react-hooks)[\\/]/.test(id)) {
|
||||||
|
return 'plebbit-react-hooks';
|
||||||
|
}
|
||||||
|
if (/[\\/]node_modules[\\/](@react-spring|@use-gesture)[\\/]/.test(id)) {
|
||||||
|
return 'spring-gesture';
|
||||||
|
}
|
||||||
if (/[\\/]node_modules[\\/](react|react-dom|react-router-dom|react-i18next|i18next|i18next-browser-languagedetector|i18next-http-backend)[\\/]/.test(id)) {
|
if (/[\\/]node_modules[\\/](react|react-dom|react-router-dom|react-i18next|i18next|i18next-browser-languagedetector|i18next-http-backend)[\\/]/.test(id)) {
|
||||||
return 'vendor';
|
return 'vendor';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user