Rename "reader scrollbar state" properties

This commit is contained in:
schroda
2025-08-31 16:38:26 +02:00
parent 4cc5821ead
commit 9bedec7115
10 changed files with 57 additions and 53 deletions

View File

@@ -16,38 +16,42 @@ interface ReaderStore {
manga: TMangaReader | undefined; manga: TMangaReader | undefined;
setManga: (manga: TMangaReader | undefined) => void; setManga: (manga: TMangaReader | undefined) => void;
scrollbar: { scrollbar: {
scrollbarXSize: number; xSize: number;
setScrollbarXSize: (size: number) => void; setXSize: (size: number) => void;
scrollbarYSize: number; ySize: number;
setScrollbarYSize: (size: number) => void; setYSize: (size: number) => void;
}; };
} }
const DEFAULT_STATE = { const DEFAULT_STATE = {
manga: undefined, manga: undefined,
} satisfies Pick<ReaderStore, 'manga'>; scrollbar: {
xSize: 0,
ySize: 0,
},
} satisfies Pick<ReaderStore, 'manga'> & { scrollbar: Pick<ReaderStore['scrollbar'], 'xSize' | 'ySize'> };
export const useReaderStore = create<ReaderStore>()( export const useReaderStore = create<ReaderStore>()(
immer((set) => ({ immer((set, get) => ({
...DEFAULT_STATE, ...DEFAULT_STATE,
reset: () => reset: () =>
set((draft) => { set((draft) => {
draft.manga = DEFAULT_STATE.manga; draft.manga = DEFAULT_STATE.manga;
draft.scrollbar = { ...get().scrollbar, ...DEFAULT_STATE.scrollbar };
}), }),
setManga: (manga) => setManga: (manga) =>
set((draft) => { set((draft) => {
draft.manga = manga; draft.manga = manga;
}), }),
scrollbar: { scrollbar: {
scrollbarXSize: 0, ...DEFAULT_STATE.scrollbar,
setScrollbarXSize: (size) => setXSize: (size) =>
set((draft) => { set((draft) => {
draft.scrollbar.scrollbarXSize = size; draft.scrollbar.xSize = size;
}), }),
scrollbarYSize: 0, setYSize: (size) =>
setScrollbarYSize: (size) =>
set((draft) => { set((draft) => {
draft.scrollbar.scrollbarYSize = size; draft.scrollbar.ySize = size;
}), }),
}, },
})), })),

View File

@@ -320,8 +320,8 @@ export const useReaderInfiniteScrollUpdateChapter = (
const elementIntersectionInfo = getElementIntersectionInfo( const elementIntersectionInfo = getElementIntersectionInfo(
readingDirection, readingDirection,
entry.target.getBoundingClientRect(), entry.target.getBoundingClientRect(),
getReaderStore().scrollbar.scrollbarXSize, getReaderStore().scrollbar.xSize,
getReaderStore().scrollbar.scrollbarYSize, getReaderStore().scrollbar.ySize,
); );
const { start: isStartIntersecting, end: isEndIntersecting } = getElementIntersection( const { start: isStartIntersecting, end: isEndIntersecting } = getElementIntersection(
elementIntersectionInfo, elementIntersectionInfo,

View File

@@ -25,7 +25,7 @@ import { reverseString } from '@/base/utils/Strings.ts';
import { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts'; import { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts';
import { TReaderProgressBarContext } from '@/features/reader/overlay/progress-bar/ReaderProgressBar.types.ts'; import { TReaderProgressBarContext } from '@/features/reader/overlay/progress-bar/ReaderProgressBar.types.ts';
import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx'; import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx';
import { useReaderStore } from '@/features/reader/ReaderStore.ts'; import { useReaderStoreShallow } from '@/features/reader/ReaderStore.ts';
const BaseReaderPageNumber = ({ const BaseReaderPageNumber = ({
isDesktop, isDesktop,
@@ -42,7 +42,7 @@ const BaseReaderPageNumber = ({
Pick<TReaderProgressBarContext, 'isMaximized'> & Pick<TReaderProgressBarContext, 'isMaximized'> &
Pick<ReaderStatePages, 'currentPageIndex' | 'pages' | 'totalPages'> & Pick<ReaderStatePages, 'currentPageIndex' | 'pages' | 'totalPages'> &
Pick<IReaderSettings, 'progressBarType' | 'shouldShowPageNumber' | 'readingDirection'>) => { Pick<IReaderSettings, 'progressBarType' | 'shouldShowPageNumber' | 'readingDirection'>) => {
const scrollbarXSize = useReaderStore((state) => state.scrollbar.scrollbarXSize); const scrollbar = useReaderStoreShallow((state) => state.scrollbar);
const pageName = useMemo(() => { const pageName = useMemo(() => {
const currentPageName = getPage(currentPageIndex, pages).name; const currentPageName = getPage(currentPageIndex, pages).name;
@@ -74,7 +74,7 @@ const BaseReaderPageNumber = ({
position: 'fixed', position: 'fixed',
left: readerNavBarWidth, left: readerNavBarWidth,
right: 0, right: 0,
bottom: (theme) => `max(calc(${theme.spacing(1)} + ${scrollbarXSize}px), env(safe-area-inset-bottom))`, bottom: (theme) => `max(calc(${theme.spacing(1)} + ${scrollbar.xSize}px), env(safe-area-inset-bottom))`,
alignItems: 'center', alignItems: 'center',
transition: (theme) => `left 0.${theme.transitions.duration.shortest}s`, transition: (theme) => `left 0.${theme.transitions.duration.shortest}s`,
}} }}

View File

@@ -33,7 +33,7 @@ import { FALLBACK_CHAPTER } from '@/features/chapter/Chapter.constants.ts';
import { FALLBACK_MANGA } from '@/features/manga/Manga.constants.ts'; import { FALLBACK_MANGA } from '@/features/manga/Manga.constants.ts';
import { ReaderExitButton } from '@/features/reader/overlay/navigation/components/ReaderExitButton.tsx'; import { ReaderExitButton } from '@/features/reader/overlay/navigation/components/ReaderExitButton.tsx';
import { requestManager } from '@/lib/requests/RequestManager.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts';
import { useReaderStore, useReaderStoreShallow } from '@/features/reader/ReaderStore.ts'; import { useReaderStoreShallow } from '@/features/reader/ReaderStore.ts';
const DEFAULT_MANGA = { ...FALLBACK_MANGA, title: '' }; const DEFAULT_MANGA = { ...FALLBACK_MANGA, title: '' };
@@ -45,7 +45,7 @@ const BaseReaderOverlayHeaderMobile = forwardRef<
const popupState = usePopupState({ popupId: 'reader-overlay-more-menu', variant: 'popover' }); const popupState = usePopupState({ popupId: 'reader-overlay-more-menu', variant: 'popover' });
const manga = useReaderStoreShallow((state) => state.manga); const manga = useReaderStoreShallow((state) => state.manga);
const scrollbarYSize = useReaderStore((state) => state.scrollbar.scrollbarYSize); const scrollbar = useReaderStoreShallow((state) => state.scrollbar);
const { id: mangaId, title } = manga ?? DEFAULT_MANGA; const { id: mangaId, title } = manga ?? DEFAULT_MANGA;
const { id: chapterId, name, realUrl, isBookmarked } = currentChapter ?? FALLBACK_CHAPTER; const { id: chapterId, name, realUrl, isBookmarked } = currentChapter ?? FALLBACK_CHAPTER;
@@ -59,7 +59,7 @@ const BaseReaderOverlayHeaderMobile = forwardRef<
position: 'fixed', position: 'fixed',
top: 0, top: 0,
left: 0, left: 0,
right: `${scrollbarYSize}px`, right: `${scrollbar.ySize}px`,
p: 2, p: 2,
pt: (theme) => `max(env(safe-area-inset-top), ${theme.spacing(2)})`, pt: (theme) => `max(env(safe-area-inset-top), ${theme.spacing(2)})`,
backgroundColor: (theme) => alpha(theme.palette.background.paper, 0.95), backgroundColor: (theme) => alpha(theme.palette.background.paper, 0.95),

View File

@@ -40,7 +40,7 @@ const BaseReaderBottomBarMobile = ({
const chapterListPopupState = usePopupState({ variant: 'dialog', popupId: 'reader-chapter-list-dialog' }); const chapterListPopupState = usePopupState({ variant: 'dialog', popupId: 'reader-chapter-list-dialog' });
const quickSettingsPopupState = usePopupState({ variant: 'dialog', popupId: 'reader-quick-settings-dialog' }); const quickSettingsPopupState = usePopupState({ variant: 'dialog', popupId: 'reader-quick-settings-dialog' });
const { scrollbarXSize, scrollbarYSize } = useReaderStoreShallow((state) => state.scrollbar); const scrollbar = useReaderStoreShallow((state) => state.scrollbar);
const [bottomBarRefHeight, setBottomBarRefHeight] = useState(0); const [bottomBarRefHeight, setBottomBarRefHeight] = useState(0);
const bottomBarRef = useRef<HTMLDivElement>(null); const bottomBarRef = useRef<HTMLDivElement>(null);
@@ -58,7 +58,7 @@ const BaseReaderBottomBarMobile = ({
<Stack <Stack
sx={{ sx={{
position: 'fixed', position: 'fixed',
right: `${scrollbarYSize}px`, right: `${scrollbar.ySize}px`,
bottom: 0, bottom: 0,
left: 0, left: 0,
height: `calc(100% - ${topOffset}px)`, height: `calc(100% - ${topOffset}px)`,
@@ -71,7 +71,7 @@ const BaseReaderBottomBarMobile = ({
sx={{ sx={{
alignItems: 'center', alignItems: 'center',
backgroundColor: (theme) => alpha(theme.palette.background.paper, 0.95), backgroundColor: (theme) => alpha(theme.palette.background.paper, 0.95),
pb: `max(${scrollbarXSize}px, env(safe-area-inset-bottom))`, pb: `max(${scrollbar.xSize}px, env(safe-area-inset-bottom))`,
boxShadow: 2, boxShadow: 2,
pointerEvents: 'all', pointerEvents: 'all',
}} }}

View File

@@ -50,7 +50,7 @@ const BaseStandardReaderProgressBar = ({
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const { scrollbarXSize, scrollbarYSize } = useReaderStoreShallow((state) => state.scrollbar); const scrollbar = useReaderStoreShallow((state) => state.scrollbar);
const [, setRefreshProgressBarPosition] = useState({}); const [, setRefreshProgressBarPosition] = useState({});
useResizeObserver( useResizeObserver(
@@ -61,8 +61,8 @@ const BaseStandardReaderProgressBar = ({
const finalProgressBarPosition = getProgressBarPosition( const finalProgressBarPosition = getProgressBarPosition(
progressBarPosition, progressBarPosition,
progressBarPositionAutoVertical, progressBarPositionAutoVertical,
scrollbarYSize, scrollbar.ySize,
readerNavBarWidth + scrollbarXSize, readerNavBarWidth + scrollbar.xSize,
); );
const { isBottom, isLeft, isRight, isVertical, isHorizontal } = const { isBottom, isLeft, isRight, isVertical, isHorizontal } =
getProgressBarPositionInfo(finalProgressBarPosition); getProgressBarPositionInfo(finalProgressBarPosition);
@@ -111,20 +111,20 @@ const BaseStandardReaderProgressBar = ({
...applyStyles(isHorizontal, { ...applyStyles(isHorizontal, {
minHeight: '100px', minHeight: '100px',
...applyStyles(theme.direction === 'ltr', { ...applyStyles(theme.direction === 'ltr', {
left: readerDirection === 'ltr' ? readerNavBarWidth : scrollbarYSize, left: readerDirection === 'ltr' ? readerNavBarWidth : scrollbar.ySize,
right: readerDirection === 'rtl' ? readerNavBarWidth : scrollbarYSize, right: readerDirection === 'rtl' ? readerNavBarWidth : scrollbar.ySize,
}), }),
...applyStyles(theme.direction === 'rtl', { ...applyStyles(theme.direction === 'rtl', {
left: readerDirection === 'rtl' ? readerNavBarWidth : scrollbarYSize, left: readerDirection === 'rtl' ? readerNavBarWidth : scrollbar.ySize,
right: readerDirection === 'ltr' ? readerNavBarWidth : scrollbarYSize, right: readerDirection === 'ltr' ? readerNavBarWidth : scrollbar.ySize,
}), }),
}), }),
...applyStyles(isVertical, { ...applyStyles(isVertical, {
minWidth: '100px', minWidth: '100px',
bottom: `${scrollbarXSize}px`, bottom: `${scrollbar.xSize}px`,
}), }),
...applyStyles(isBottom, { ...applyStyles(isBottom, {
bottom: `${scrollbarXSize}px`, bottom: `${scrollbar.xSize}px`,
}), }),
...applyStyles(isLeft, { ...applyStyles(isLeft, {
...applyStyles(theme.direction === 'ltr', { ...applyStyles(theme.direction === 'ltr', {
@@ -132,14 +132,14 @@ const BaseStandardReaderProgressBar = ({
right: readerDirection === 'rtl' ? readerNavBarWidth : 'unset', right: readerDirection === 'rtl' ? readerNavBarWidth : 'unset',
}), }),
...applyStyles(theme.direction === 'rtl', { ...applyStyles(theme.direction === 'rtl', {
right: readerDirection === 'rtl' ? scrollbarYSize : 'unset', right: readerDirection === 'rtl' ? scrollbar.ySize : 'unset',
left: readerDirection === 'ltr' ? scrollbarYSize : 'unset', left: readerDirection === 'ltr' ? scrollbar.ySize : 'unset',
}), }),
}), }),
...applyStyles(isRight, { ...applyStyles(isRight, {
...applyStyles(theme.direction === 'ltr', { ...applyStyles(theme.direction === 'ltr', {
right: readerDirection === 'ltr' ? scrollbarYSize : 'unset', right: readerDirection === 'ltr' ? scrollbar.ySize : 'unset',
left: readerDirection === 'rtl' ? scrollbarYSize : 'unset', left: readerDirection === 'rtl' ? scrollbar.ySize : 'unset',
}), }),
...applyStyles(theme.direction === 'rtl', { ...applyStyles(theme.direction === 'rtl', {
left: readerDirection === 'rtl' ? readerNavBarWidth : 'unset', left: readerDirection === 'rtl' ? readerNavBarWidth : 'unset',

View File

@@ -38,7 +38,7 @@ import { applyStyles } from '@/base/utils/ApplyStyles.ts';
import { useResizeObserver } from '@/base/hooks/useResizeObserver.tsx'; import { useResizeObserver } from '@/base/hooks/useResizeObserver.tsx';
import { getProgressBarPosition } from '@/features/reader/settings/ReaderSettings.utils.tsx'; import { getProgressBarPosition } from '@/features/reader/settings/ReaderSettings.utils.tsx';
import { ReaderControls } from '@/features/reader/services/ReaderControls.ts'; import { ReaderControls } from '@/features/reader/services/ReaderControls.ts';
import { useReaderStore } from '@/features/reader/ReaderStore.ts'; import { useReaderStoreShallow } from '@/features/reader/ReaderStore.ts';
const PROGRESS_BAR_POSITION_TO_SLIDE_DIRECTION: Record<ProgressBarPosition, SlideProps['direction']> = { const PROGRESS_BAR_POSITION_TO_SLIDE_DIRECTION: Record<ProgressBarPosition, SlideProps['direction']> = {
[ProgressBarPosition.BOTTOM]: 'up', [ProgressBarPosition.BOTTOM]: 'up',
@@ -71,7 +71,7 @@ const BaseMobileReaderProgressBar = ({
bottomOffset?: number; bottomOffset?: number;
}) => { }) => {
const openChapter = ReaderControls.useOpenChapter(); const openChapter = ReaderControls.useOpenChapter();
const scrollbarXSize = useReaderStore((state) => state.scrollbar.scrollbarXSize); const scrollbar = useReaderStoreShallow((state) => state.scrollbar);
const [, setRefreshProgressBarPosition] = useState({}); const [, setRefreshProgressBarPosition] = useState({});
useResizeObserver( useResizeObserver(
@@ -84,7 +84,7 @@ const BaseMobileReaderProgressBar = ({
progressBarPositionAutoVertical, progressBarPositionAutoVertical,
// scrollbar x size is already included in the top/bottom offset due to the progress bar being placed in the reader mobile bottom bar // scrollbar x size is already included in the top/bottom offset due to the progress bar being placed in the reader mobile bottom bar
topOffset + bottomOffset, topOffset + bottomOffset,
scrollbarXSize, scrollbar.xSize,
); );
const { isLeft, isRight, isVertical, isHorizontal } = getProgressBarPositionInfo(finalProgressBarPosition); const { isLeft, isRight, isVertical, isHorizontal } = getProgressBarPositionInfo(finalProgressBarPosition);

View File

@@ -180,8 +180,8 @@ const BaseReaderViewer = forwardRef(
const scrollbarYSize = MediaQuery.useGetScrollbarSize('height', scrollElementRef.current); const scrollbarYSize = MediaQuery.useGetScrollbarSize('height', scrollElementRef.current);
useLayoutEffect(() => { useLayoutEffect(() => {
const { scrollbar } = getReaderStore(); const { scrollbar } = getReaderStore();
scrollbar.setScrollbarXSize(scrollbarXSize); scrollbar.setXSize(scrollbarXSize);
scrollbar.setScrollbarYSize(scrollbarYSize); scrollbar.setYSize(scrollbarYSize);
}, [scrollbarXSize, scrollbarYSize]); }, [scrollbarXSize, scrollbarYSize]);
const handleClick = ReaderControls.useHandleClick(scrollElementRef.current); const handleClick = ReaderControls.useHandleClick(scrollElementRef.current);

View File

@@ -86,7 +86,7 @@ const BaseReaderPage = ({
const { src } = props; const { src } = props;
const isTabletWidth = MediaQuery.useIsTabletWidth(); const isTabletWidth = MediaQuery.useIsTabletWidth();
const { scrollbarXSize, scrollbarYSize } = useReaderStoreShallow((state) => state.scrollbar); const scrollbar = useReaderStoreShallow((state) => state.scrollbar);
const handleLoad = useCallback( const handleLoad = useCallback(
() => onLoad?.(pagesIndex, src, isPrimaryPage), () => onLoad?.(pagesIndex, src, isPrimaryPage),
@@ -114,8 +114,8 @@ const BaseReaderPage = ({
shouldStretchPage, shouldStretchPage,
pageScaleMode, pageScaleMode,
readerWidth, readerWidth,
readerNavBarWidth + scrollbarYSize, readerNavBarWidth + scrollbar.ySize,
scrollbarXSize, scrollbar.xSize,
doublePage, doublePage,
isTabletWidth, isTabletWidth,
), ),
@@ -131,8 +131,8 @@ const BaseReaderPage = ({
pageScaleMode, pageScaleMode,
doublePage, doublePage,
readerWidth, readerWidth,
readerNavBarWidth + scrollbarYSize, readerNavBarWidth + scrollbar.ySize,
scrollbarXSize, scrollbar.xSize,
), ),
filter: getCustomFilterString(customFilter), filter: getCustomFilterString(customFilter),
objectFit: 'contain', objectFit: 'contain',

View File

@@ -107,7 +107,7 @@ const BaseReaderTransitionPage = ({
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const manga = useReaderStoreShallow((state) => state.manga); const manga = useReaderStoreShallow((state) => state.manga);
const { scrollbarXSize, scrollbarYSize } = useReaderStoreShallow((state) => state.scrollbar); const scrollbar = useReaderStoreShallow((state) => state.scrollbar);
const isPreviousType = type === ReaderTransitionPageMode.PREVIOUS; const isPreviousType = type === ReaderTransitionPageMode.PREVIOUS;
const isNextType = type === ReaderTransitionPageMode.NEXT; const isNextType = type === ReaderTransitionPageMode.NEXT;
@@ -141,13 +141,13 @@ const BaseReaderTransitionPage = ({
position: 'sticky', position: 'sticky',
...applyStyles(isContinuousVerticalReadingMode(readingMode), { ...applyStyles(isContinuousVerticalReadingMode(readingMode), {
left: 0, left: 0,
maxWidth: `calc(100vw - ${scrollbarYSize}px - ${readerNavBarWidth}px)`, maxWidth: `calc(100vw - ${scrollbar.ySize}px - ${readerNavBarWidth}px)`,
minHeight: `calc(100vh - ${scrollbarXSize}px)`, minHeight: `calc(100vh - ${scrollbar.xSize}px)`,
}), }),
...applyStyles(readingMode === ReadingMode.CONTINUOUS_HORIZONTAL, { ...applyStyles(readingMode === ReadingMode.CONTINUOUS_HORIZONTAL, {
top: 0, top: 0,
minWidth: `calc(100vw - ${scrollbarYSize}px - ${readerNavBarWidth}px)`, minWidth: `calc(100vw - ${scrollbar.ySize}px - ${readerNavBarWidth}px)`,
maxHeight: `calc(100vh - ${scrollbarXSize}px)`, maxHeight: `calc(100vh - ${scrollbar.xSize}px)`,
}), }),
}), }),
}} }}
@@ -157,8 +157,8 @@ const BaseReaderTransitionPage = ({
gap: 2, gap: 2,
maxWidth: (theme) => maxWidth: (theme) =>
// spacing = added padding left + right // spacing = added padding left + right
`calc(100vw - ${scrollbarYSize}px - ${readerNavBarWidth}px - ${theme.spacing(2)})`, `calc(100vw - ${scrollbar.ySize}px - ${readerNavBarWidth}px - ${theme.spacing(2)})`,
maxHeight: `calc(100vh - ${scrollbarXSize}px)`, maxHeight: `calc(100vh - ${scrollbar.xSize}px)`,
width: 'max-content', width: 'max-content',
p: 1, p: 1,
}} }}