mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
refactor(home): prevent layout shift in popular threads loading
Remove boards list loading state since default data is available synchronously. Add min-height to popular threads loading state to reserve space and prevent container resize. Left-align loading text in popular threads.
This commit is contained in:
@@ -2,7 +2,6 @@ import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDefaultSubplebbitsState, useDefaultSubplebbits, MultisubSubplebbit } from '../../../hooks/use-default-subplebbits';
|
||||
import { getBoardPath } from '../../../lib/utils/route-utils';
|
||||
import LoadingEllipsis from '../../../components/loading-ellipsis';
|
||||
import useDisclaimerModalStore from '../../../stores/use-disclaimer-modal-store';
|
||||
import useDirectoryModalStore from '../../../stores/use-directory-modal-store';
|
||||
import useBoardsFilterStore from '../../../stores/use-boards-filter-store';
|
||||
@@ -31,7 +30,7 @@ const NSFWBadge = () => {
|
||||
const BoardsList = ({ multisub }: { multisub: MultisubSubplebbit[] }) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const { loading, error } = useDefaultSubplebbitsState();
|
||||
const { error } = useDefaultSubplebbitsState();
|
||||
const { showDisclaimerModal } = useDisclaimerModalStore();
|
||||
const { openDirectoryModal } = useDirectoryModalStore();
|
||||
const { useCatalogLinks, boardFilter } = useBoardsFilterStore();
|
||||
@@ -56,37 +55,10 @@ const BoardsList = ({ multisub }: { multisub: MultisubSubplebbit[] }) => {
|
||||
openDirectoryModal();
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={styles.box}>
|
||||
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
|
||||
<h2 className='capitalize'>{t('boards')}</h2>
|
||||
<BoardsFilterModal />
|
||||
</div>
|
||||
<div className={styles.boxContent}>
|
||||
<LoadingEllipsis string={t('loading_default_boards')} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className={styles.box}>
|
||||
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
|
||||
<h2 className='capitalize'>{t('boards')}</h2>
|
||||
<BoardsFilterModal />
|
||||
</div>
|
||||
<div className={styles.boxContent}>
|
||||
<div className='red'>{error.message}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Find active boards
|
||||
const bizAddress = findBoardAddress(multisub, '/biz/ - Business & Finance');
|
||||
const polAddress = findBoardAddress(multisub, '/pol/ - Politically Incorrect');
|
||||
const errorMessage = error?.message;
|
||||
|
||||
// Filtering logic: determine which categories to show
|
||||
const showAll = boardFilter === 'all';
|
||||
@@ -110,6 +82,7 @@ const BoardsList = ({ multisub }: { multisub: MultisubSubplebbit[] }) => {
|
||||
<BoardsFilterModal />
|
||||
</div>
|
||||
<div className={`${styles.boxContent} ${styles.boardsContent}`}>
|
||||
{errorMessage && <div className='red'>{errorMessage}</div>}
|
||||
{/* Column 1: Japanese Culture + Video Games */}
|
||||
{(showJapaneseCulture || showVideoGames) && (
|
||||
<div className={styles.boardsColumn}>
|
||||
|
||||
@@ -190,6 +190,12 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.popularThreadsLoading {
|
||||
text-align: left;
|
||||
/* Reserve space only while loading: max 8 posts, ~2 rows of 4 cards on desktop */
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
.popularThread {
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
@@ -351,6 +357,11 @@
|
||||
.boardsColumn a {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
/* Mobile: popular threads cards stack more, so taller min-height needed */
|
||||
.popularThreadsLoading {
|
||||
min-height: 1200px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
|
||||
@@ -78,6 +78,7 @@ const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: MultisubSubple
|
||||
|
||||
const filteredSubplebbits = useMemo(getFilteredSubplebbits, [subplebbits, showWorksafeContentOnly, showNsfwContentOnly, multisub]);
|
||||
const { popularPosts } = usePopularPosts(filteredSubplebbits);
|
||||
const isLoading = popularPosts.length === 0;
|
||||
|
||||
return (
|
||||
<div className={styles.box}>
|
||||
@@ -85,12 +86,8 @@ const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: MultisubSubple
|
||||
<h2 className='capitalize'>{t('popular_threads')}</h2>
|
||||
<BoxModal />
|
||||
</div>
|
||||
<div className={`${styles.boxContent} ${popularPosts.length !== 0 ? styles.popularThreads : ''}`}>
|
||||
{popularPosts.length === 0 ? (
|
||||
<LoadingEllipsis string={t('loading')} />
|
||||
) : (
|
||||
popularPosts.map((post: any) => <PopularThreadCard key={post.cid} post={post} multisub={multisub} />)
|
||||
)}
|
||||
<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} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user