diff --git a/src/modules/browse/screens/Browse.tsx b/src/modules/browse/screens/Browse.tsx index 12f5503d..58961b85 100644 --- a/src/modules/browse/screens/Browse.tsx +++ b/src/modules/browse/screens/Browse.tsx @@ -60,7 +60,7 @@ export function Browse() { - + diff --git a/src/modules/chapter/components/ChapterList.tsx b/src/modules/chapter/components/ChapterList.tsx index bd45080b..f155cec8 100644 --- a/src/modules/chapter/components/ChapterList.tsx +++ b/src/modules/chapter/components/ChapterList.tsx @@ -47,6 +47,7 @@ import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx'; import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx'; import { shouldForwardProp } from '@/modules/core/utils/ShouldForwardProp.ts'; import { useChapterOptions } from '@/modules/chapter/hooks/useChapterOptions.tsx'; +import { getErrorMessage } from '@/lib/HelperFunctions.ts'; type ChapterListHeaderProps = { scrollbarWidth: number; @@ -175,7 +176,7 @@ export const ChapterList = ({ refetch().catch(defaultPromiseErrorHandler('ChapterList::refetch'))} /> diff --git a/src/modules/core/components/placeholder/EmptyView.tsx b/src/modules/core/components/placeholder/EmptyView.tsx index 073c510a..ae339114 100644 --- a/src/modules/core/components/placeholder/EmptyView.tsx +++ b/src/modules/core/components/placeholder/EmptyView.tsx @@ -27,10 +27,11 @@ export interface EmptyViewProps { messageExtra?: JSX.Element | string; retry?: () => void; noFaces?: boolean; + topOffset?: number; sx?: SxProps; } -export function EmptyView({ message, messageExtra, retry, noFaces, sx }: EmptyViewProps) { +export function EmptyView({ message, messageExtra, retry, noFaces, topOffset = 0, sx }: EmptyViewProps) { const { t } = useTranslation(); const errorFace = useMemo(() => getRandomErrorFace(), []); @@ -41,7 +42,9 @@ export function EmptyView({ message, messageExtra, retry, noFaces, sx }: EmptyVi textAlign: 'center', alignItems: 'center', justifyContent: 'center', - height: '100%', + minWidth: '100%', + minHeight: `calc(100% - ${topOffset}px)`, + mt: `${topOffset}px`, ...sx, }} > @@ -51,7 +54,9 @@ export function EmptyView({ message, messageExtra, retry, noFaces, sx }: EmptyVi )} {message} - {messageExtra} + + {messageExtra} + {retry && } ); diff --git a/src/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx b/src/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx index 88abbaee..19c6e003 100644 --- a/src/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx +++ b/src/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx @@ -14,10 +14,8 @@ export function EmptyViewAbsoluteCentered({ sx, ...emptyViewProps }: EmptyViewPr {...emptyViewProps} sx={{ position: 'absolute', - height: undefined, - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', + top: 0, + left: 0, ...sx, }} /> diff --git a/src/modules/extension/screens/Extensions.tsx b/src/modules/extension/screens/Extensions.tsx index 88103edc..cf7d48fe 100644 --- a/src/modules/extension/screens/Extensions.tsx +++ b/src/modules/extension/screens/Extensions.tsx @@ -207,6 +207,7 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) { fetchExtensions().catch(defaultPromiseErrorHandler('Extensions::refetchExtensions')); } }} + topOffset={tabsMenuHeight} /> ); } diff --git a/src/modules/manga/components/MangaGrid.tsx b/src/modules/manga/components/MangaGrid.tsx index f5a3e81f..aa7e177e 100644 --- a/src/modules/manga/components/MangaGrid.tsx +++ b/src/modules/manga/components/MangaGrid.tsx @@ -238,6 +238,7 @@ export const MangaGrid: React.FC = ({ isLoading, message, messageExtra, + topOffset, hasNextPage, loadMore, gridLayout, @@ -348,6 +349,7 @@ export const MangaGrid: React.FC = ({ message={message ?? t('manga.error.label.no_mangas_found')} messageExtra={messageExtra} retry={retry} + topOffset={topOffset} /> ); } diff --git a/src/modules/migration/screens/Migration.tsx b/src/modules/migration/screens/Migration.tsx index 61491692..2fd61b22 100644 --- a/src/modules/migration/screens/Migration.tsx +++ b/src/modules/migration/screens/Migration.tsx @@ -104,6 +104,7 @@ export const Migration = ({ tabsMenuHeight }: { tabsMenuHeight: number }) => { message={t('global.error.label.failed_to_load_data')} messageExtra={error.message} retry={() => refetch().catch(defaultPromiseErrorHandler('Migration::refetch'))} + topOffset={tabsMenuHeight} /> ); } diff --git a/src/modules/source/screens/SourceMangas.tsx b/src/modules/source/screens/SourceMangas.tsx index a97c75c3..f951db10 100644 --- a/src/modules/source/screens/SourceMangas.tsx +++ b/src/modules/source/screens/SourceMangas.tsx @@ -53,6 +53,7 @@ import { MangaIdInfo } from '@/modules/manga/Manga.types.ts'; import { GridLayout } from '@/modules/core/Core.types.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; +import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx'; const DEFAULT_SOURCE: Pick = { id: '-1' }; @@ -249,6 +250,16 @@ export function SourceMangas() { const currentQuery = useRef(query); const currentAbortRequest = useRef<(reason: any) => void>(() => {}); + const contentTypeMenuRef = useRef(null); + const [contentTypeMenuHeight, setContentTypeMenuHeight] = useState(0); + useResizeObserver( + contentTypeMenuRef, + useCallback( + () => setContentTypeMenuHeight(contentTypeMenuRef.current?.clientHeight ?? 0), + [contentTypeMenuRef], + ), + ); + const didSearchChange = currentQuery.current !== query; if (didSearchChange && contentType === SourceContentType.SEARCH) { currentQuery.current = query; @@ -428,9 +439,11 @@ export function SourceMangas() { }; }, [t, source]); + const EmptyViewComponent = mangas.length ? EmptyView : EmptyViewAbsoluteCentered; + return ( - + } @@ -466,6 +479,7 @@ export function SourceMangas() { loadMore={loadMore} message={message} messageExtra={messageExtra} + topOffset={contentTypeMenuHeight} isLoading={isLoading} gridLayout={sourceGridLayout} mode="source" @@ -473,18 +487,12 @@ export function SourceMangas() { /> )} - {error && !mangas.length && ( - loadPage(lastPageNum).catch(defaultPromiseErrorHandler('SourceMangas::refetch'))} - /> - )} - {error && !!mangas.length && ( - loadPage(lastPageNum).catch(defaultPromiseErrorHandler('SourceMangas::refetch'))} + topOffset={contentTypeMenuHeight} /> )} diff --git a/src/modules/source/screens/Sources.tsx b/src/modules/source/screens/Sources.tsx index df2ec84f..e0491e6d 100644 --- a/src/modules/source/screens/Sources.tsx +++ b/src/modules/source/screens/Sources.tsx @@ -62,7 +62,7 @@ function groupByLang>( return result; } -export function Sources() { +export function Sources({ tabsMenuHeight }: { tabsMenuHeight: number }) { const { t } = useTranslation(); const { setAction } = useContext(NavBarContext); @@ -138,12 +138,15 @@ export function Sources() { message={t('global.error.label.failed_to_load_data')} messageExtra={error.message} retry={() => refetch().catch(defaultPromiseErrorHandler('Sources::refetch'))} + topOffset={tabsMenuHeight} /> ); } if (sources?.length === 0) { - return ; + return ( + + ); } return (