Properly update chapter list window scroll
Once the window scroller was set, resizing the window to increase the width did not remove the window scroller again
This commit is contained in:
@@ -11,7 +11,7 @@ import Stack from '@mui/material/Stack';
|
|||||||
import Tooltip from '@mui/material/Tooltip';
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import { styled } from '@mui/material/styles';
|
import { styled } from '@mui/material/styles';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { ComponentProps, useMemo } from 'react';
|
import { ComponentProps, useCallback, useMemo, useState } from 'react';
|
||||||
import { Virtuoso } from 'react-virtuoso';
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
@@ -42,27 +42,29 @@ import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts
|
|||||||
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
|
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
|
||||||
import { GET_CHAPTERS_MANGA } from '@/lib/graphql/queries/ChapterQuery.ts';
|
import { GET_CHAPTERS_MANGA } from '@/lib/graphql/queries/ChapterQuery.ts';
|
||||||
import { Mangas } from '@/lib/data/Mangas';
|
import { Mangas } from '@/lib/data/Mangas';
|
||||||
|
import { useNavBarContext } from '@/components/context/NavbarContext.tsx';
|
||||||
|
import { useResizeObserver } from '@/util/useResizeObserver.tsx';
|
||||||
|
import { MediaQuery } from '@/lib/ui/MediaQuery.tsx';
|
||||||
|
|
||||||
const ChapterListHeader = styled(Stack)(({ theme }) => ({
|
const ChapterListHeader = styled(Stack)(({ theme }) => ({
|
||||||
margin: 8,
|
padding: theme.spacing(1),
|
||||||
marginBottom: 0,
|
paddingRight: `calc(14px + ${theme.spacing(1)})`,
|
||||||
marginRight: '10px',
|
paddingBottom: 0,
|
||||||
minHeight: 40,
|
|
||||||
[theme.breakpoints.down('md')]: {
|
[theme.breakpoints.down('md')]: {
|
||||||
marginRight: 0,
|
paddingRight: theme.spacing(1),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledVirtuoso = styled(Virtuoso)(({ theme }) => ({
|
const StyledVirtuoso = styled(Virtuoso, { shouldForwardProp: (prop) => prop !== 'topOffset' })<{ topOffset: number }>(
|
||||||
|
({ theme, topOffset }) => ({
|
||||||
listStyle: 'none',
|
listStyle: 'none',
|
||||||
padding: 0,
|
padding: 0,
|
||||||
minHeight: '200px',
|
|
||||||
[theme.breakpoints.up('md')]: {
|
[theme.breakpoints.up('md')]: {
|
||||||
// 64px for the Appbar, 48px for the ChapterCount Header
|
height: `calc(100vh - ${topOffset}px)`,
|
||||||
height: 'calc(100vh - 64px - 48px)',
|
|
||||||
margin: 0,
|
margin: 0,
|
||||||
},
|
},
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export interface IChapterWithMeta extends ChapterWithMetaType<ComponentProps<typeof ChapterCard>['chapter']> {
|
export interface IChapterWithMeta extends ChapterWithMetaType<ComponentProps<typeof ChapterCard>['chapter']> {
|
||||||
selected: boolean | null;
|
selected: boolean | null;
|
||||||
@@ -76,6 +78,16 @@ export const ChapterList = ({
|
|||||||
isRefreshing: boolean;
|
isRefreshing: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { appBarHeight } = useNavBarContext();
|
||||||
|
|
||||||
|
const isMobileWidth = MediaQuery.useIsBelowWidth('md');
|
||||||
|
|
||||||
|
const [chapterListHeaderHeight, setChapterListHeaderHeight] = useState(0);
|
||||||
|
const [chapterListHeaderRef, setChapterListHeaderRef] = useState<HTMLDivElement | null>(null);
|
||||||
|
useResizeObserver(
|
||||||
|
chapterListHeaderRef,
|
||||||
|
useCallback(() => setChapterListHeaderHeight(chapterListHeaderRef?.offsetHeight ?? 0), [chapterListHeaderRef]),
|
||||||
|
);
|
||||||
|
|
||||||
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
||||||
const queue = downloaderData?.downloadStatus.queue ?? [];
|
const queue = downloaderData?.downloadStatus.queue ?? [];
|
||||||
@@ -165,7 +177,12 @@ export const ChapterList = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack direction="column" sx={{ position: 'relative', flexBasis: '60%' }}>
|
<Stack direction="column" sx={{ position: 'relative', flexBasis: '60%' }}>
|
||||||
<ChapterListHeader direction="row" alignItems="center" justifyContent="space-between">
|
<ChapterListHeader
|
||||||
|
ref={setChapterListHeaderRef}
|
||||||
|
direction="row"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="space-between"
|
||||||
|
>
|
||||||
<Typography variant="h5">
|
<Typography variant="h5">
|
||||||
{`${visibleChapters.length} ${t('chapter.title_one', {
|
{`${visibleChapters.length} ${t('chapter.title_one', {
|
||||||
count: visibleChapters.length,
|
count: visibleChapters.length,
|
||||||
@@ -224,11 +241,10 @@ export const ChapterList = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<StyledVirtuoso
|
<StyledVirtuoso
|
||||||
|
topOffset={appBarHeight + chapterListHeaderHeight}
|
||||||
style={{
|
style={{
|
||||||
// override Virtuoso default values and set them with class
|
// override Virtuoso default values and set them with class
|
||||||
height: 'undefined',
|
height: 'undefined',
|
||||||
// 900 is the md breakpoint in MUI
|
|
||||||
overflowY: window.innerWidth < 900 ? 'visible' : 'auto',
|
|
||||||
}}
|
}}
|
||||||
components={{ Footer: () => <Box sx={{ paddingBottom: DEFAULT_FULL_FAB_HEIGHT }} /> }}
|
components={{ Footer: () => <Box sx={{ paddingBottom: DEFAULT_FULL_FAB_HEIGHT }} /> }}
|
||||||
totalCount={visibleChapters.length}
|
totalCount={visibleChapters.length}
|
||||||
@@ -242,7 +258,7 @@ export const ChapterList = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
useWindowScroll={window.innerWidth < 900}
|
useWindowScroll={isMobileWidth}
|
||||||
overscan={window.innerHeight * 0.5}
|
overscan={window.innerHeight * 0.5}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||||
|
import { Breakpoint } from '@mui/material/styles';
|
||||||
import { getCurrentTheme } from '@/theme.ts';
|
import { getCurrentTheme } from '@/theme.ts';
|
||||||
|
|
||||||
export class MediaQuery {
|
export class MediaQuery {
|
||||||
@@ -14,7 +15,11 @@ export class MediaQuery {
|
|||||||
return useMediaQuery('not (pointer: fine)');
|
return useMediaQuery('not (pointer: fine)');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static useIsBelowWidth(breakpoint: Breakpoint): boolean {
|
||||||
|
return useMediaQuery(getCurrentTheme().breakpoints.down(breakpoint));
|
||||||
|
}
|
||||||
|
|
||||||
static useIsMobileWidth(): boolean {
|
static useIsMobileWidth(): boolean {
|
||||||
return useMediaQuery(getCurrentTheme().breakpoints.down('sm'));
|
return this.useIsBelowWidth('sm');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
import { RefObject, useLayoutEffect, useState } from 'react';
|
import { RefObject, useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
export const useResizeObserver = (
|
export const useResizeObserver = (
|
||||||
ref: RefObject<HTMLElement> | HTMLElement | undefined,
|
ref: RefObject<HTMLElement> | HTMLElement | undefined | null,
|
||||||
callback: ResizeObserverCallback,
|
callback: ResizeObserverCallback,
|
||||||
): (() => void) => {
|
): (() => void) => {
|
||||||
const [disconnect, setDisconnect] = useState<() => void>(() => {});
|
const [disconnect, setDisconnect] = useState<() => void>(() => {});
|
||||||
|
|||||||
Reference in New Issue
Block a user