Add "Webtoon" reading mode
This commit is contained in:
24
src/assets/icons/svg/WebtoonPageIcon.tsx
Normal file
24
src/assets/icons/svg/WebtoonPageIcon.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import SvgIcon from '@mui/material/SvgIcon';
|
||||
|
||||
export const WebtoonPageIcon = () => (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M20 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V2m0 20v-8a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8"
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
@@ -62,6 +62,7 @@ const CONTINUOUS_READING_MODE_TO_SCROLL_DIRECTION: Record<ReadingMode, ScrollDir
|
||||
[ReadingMode.DOUBLE_PAGE]: ScrollDirection.Y,
|
||||
[ReadingMode.CONTINUOUS_VERTICAL]: ScrollDirection.Y,
|
||||
[ReadingMode.CONTINUOUS_HORIZONTAL]: ScrollDirection.X,
|
||||
[ReadingMode.WEBTOON]: ScrollDirection.Y,
|
||||
};
|
||||
|
||||
export const ReaderHotkeys = ({
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IReaderSettingsWithDefaultFlag } from '@/modules/reader/types/Reader.types.ts';
|
||||
import { IReaderSettingsWithDefaultFlag, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
|
||||
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
|
||||
import { DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
|
||||
import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
||||
@@ -21,7 +21,7 @@ export const ReaderSettingPageGap = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isChangeable = isContinuousReadingMode(readingMode.value);
|
||||
const isChangeable = readingMode.value !== ReadingMode.WEBTOON && isContinuousReadingMode(readingMode.value);
|
||||
if (!isChangeable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ import { isTransitionPageVisible } from '@/modules/reader/utils/ReaderPager.util
|
||||
import { useBackButton } from '@/modules/core/hooks/useBackButton.ts';
|
||||
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||
import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
||||
import {
|
||||
isContinuousReadingMode,
|
||||
isContinuousVerticalReadingMode,
|
||||
} from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
|
||||
@@ -94,7 +97,7 @@ export const ReaderTransitionPage = ({
|
||||
...applyStyles(isContinuousReadingMode(readingMode), {
|
||||
position: 'relative',
|
||||
transform: 'scale(1)',
|
||||
...applyStyles(readingMode === ReadingMode.CONTINUOUS_VERTICAL, {
|
||||
...applyStyles(isContinuousVerticalReadingMode(readingMode), {
|
||||
maxWidth: '100%',
|
||||
width: '100%',
|
||||
...applyStyles(!isFitWidthPageScaleMode, { alignItems: 'baseline' }),
|
||||
@@ -120,7 +123,7 @@ export const ReaderTransitionPage = ({
|
||||
// on small screens with "fit to with" enabled, "left 50%" does not center the element in the
|
||||
// viewport which then causes "translate" to move the element mostly outside the viewport with
|
||||
// only a small part of it being visible
|
||||
!isFitWidthPageScaleMode && readingMode === ReadingMode.CONTINUOUS_VERTICAL,
|
||||
!isFitWidthPageScaleMode && isContinuousVerticalReadingMode(readingMode),
|
||||
{
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
|
||||
@@ -45,6 +45,7 @@ const READING_MODE_TO_IN_VIEWPORT_TYPE: Record<ReadingMode, PageInViewportType>
|
||||
[ReadingMode.DOUBLE_PAGE]: PageInViewportType.X,
|
||||
[ReadingMode.CONTINUOUS_VERTICAL]: PageInViewportType.Y,
|
||||
[ReadingMode.CONTINUOUS_HORIZONTAL]: PageInViewportType.X,
|
||||
[ReadingMode.WEBTOON]: PageInViewportType.Y,
|
||||
};
|
||||
|
||||
export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | null>) => {
|
||||
@@ -111,6 +112,7 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
||||
case ReadingMode.DOUBLE_PAGE:
|
||||
return ReaderDoublePagedPager;
|
||||
case ReadingMode.CONTINUOUS_VERTICAL:
|
||||
case ReadingMode.WEBTOON:
|
||||
return ReaderVerticalPager;
|
||||
case ReadingMode.CONTINUOUS_HORIZONTAL:
|
||||
return ReaderHorizontalPager;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
|
||||
import { ReaderPagerProps } from '@/modules/reader/types/Reader.types.ts';
|
||||
import { ReaderPagerProps, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
|
||||
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||
|
||||
export const ReaderVerticalPager = ({
|
||||
@@ -20,7 +20,9 @@ export const ReaderVerticalPager = ({
|
||||
}: ReaderPagerProps) => {
|
||||
const { currentPageIndex, totalPages } = props;
|
||||
|
||||
const { pageGap } = ReaderService.useSettings();
|
||||
const { readingMode, pageGap } = ReaderService.useSettings();
|
||||
const isWebtoonMode = readingMode.value === ReadingMode.WEBTOON;
|
||||
const actualPageGap = isWebtoonMode ? 0 : pageGap;
|
||||
|
||||
return (
|
||||
<BasePager
|
||||
@@ -46,7 +48,7 @@ export const ReaderVerticalPager = ({
|
||||
margin: 'auto',
|
||||
flexWrap: 'nowrap',
|
||||
alignItems: 'center',
|
||||
gap: `${pageGap.value}px`,
|
||||
gap: `${actualPageGap}px`,
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -33,6 +33,7 @@ import { ContinuousVerticalPageIcon } from '@/assets/icons/svg/ContinuousVertica
|
||||
import { ContinuousHorizontalPageIcon } from '@/assets/icons/svg/ContinuousHorizontalPageIcon.tsx';
|
||||
import { TranslationKey } from '@/Base.types.ts';
|
||||
import { TapZoneLayouts } from '@/modules/reader/types/TapZoneLayout.types.ts';
|
||||
import { WebtoonPageIcon } from '@/assets/icons/svg/WebtoonPageIcon.tsx';
|
||||
|
||||
export const DEFAULT_READER_PROFILE = ReadingMode.SINGLE_PAGE;
|
||||
|
||||
@@ -188,6 +189,10 @@ export const READING_MODE_VALUE_TO_DISPLAY_DATA = {
|
||||
title: 'reader.settings.reader_type.label.continuous_horizontal',
|
||||
icon: <ContinuousHorizontalPageIcon />,
|
||||
},
|
||||
[ReadingMode.WEBTOON]: {
|
||||
title: 'reader.settings.reader_type.label.webtoon',
|
||||
icon: <WebtoonPageIcon />,
|
||||
},
|
||||
} satisfies ValueToDisplayData<ReadingMode>;
|
||||
|
||||
export const READING_MODE_VALUES = Object.values(ReadingMode).filter((value) => typeof value === 'number');
|
||||
|
||||
@@ -33,6 +33,7 @@ export enum ReadingMode {
|
||||
DOUBLE_PAGE,
|
||||
CONTINUOUS_VERTICAL,
|
||||
CONTINUOUS_HORIZONTAL,
|
||||
WEBTOON,
|
||||
}
|
||||
|
||||
export enum ReaderPageScaleMode {
|
||||
|
||||
@@ -17,7 +17,11 @@ import {
|
||||
ReadingMode,
|
||||
} from '@/modules/reader/types/Reader.types.ts';
|
||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||
import { isContinuousReadingMode, isReaderWidthEditable } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
||||
import {
|
||||
isContinuousReadingMode,
|
||||
isContinuousVerticalReadingMode,
|
||||
isReaderWidthEditable,
|
||||
} from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
||||
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { ReaderPage } from '@/modules/reader/components/viewer/ReaderPage.tsx';
|
||||
@@ -71,6 +75,10 @@ export const getImagePlaceholderStyling = (
|
||||
minWidth: DEFAULT_SINGLE_PAGE_WIDTH,
|
||||
minHeight: `calc(${DEFAULT_SINGLE_PAGE_HEIGHT} - ${scrollbarXSize}px)`,
|
||||
},
|
||||
[ReadingMode.WEBTOON]: {
|
||||
minWidth: `calc(${DEFAULT_SINGLE_PAGE_WIDTH} - ${scrollbarYSize}px)`,
|
||||
minHeight: '100vh',
|
||||
},
|
||||
};
|
||||
const defaultStyling = READING_MODE_TO_PLACEHOLDER_SIZE[readingMode];
|
||||
const minWidthForStretch = isDoublePage ? '50%' : '100%';
|
||||
@@ -91,7 +99,7 @@ export const getImagePlaceholderStyling = (
|
||||
...defaultStyling,
|
||||
...applyStyles(shouldStretchPage, {
|
||||
minHeight: `calc(100vh - ${scrollbarXSize}px)`,
|
||||
...applyStyles(readingMode === ReadingMode.CONTINUOUS_VERTICAL, {
|
||||
...applyStyles(isContinuousVerticalReadingMode(readingMode), {
|
||||
minHeight: '100vh',
|
||||
}),
|
||||
}),
|
||||
@@ -105,7 +113,7 @@ export const getImagePlaceholderStyling = (
|
||||
...applyStyles(shouldStretchPage, {
|
||||
minWidth: minWidthForStretch,
|
||||
minHeight: `calc(100vh - ${scrollbarXSize}px)`,
|
||||
...applyStyles(readingMode === ReadingMode.CONTINUOUS_VERTICAL, {
|
||||
...applyStyles(isContinuousVerticalReadingMode(readingMode), {
|
||||
minHeight: '100vh',
|
||||
}),
|
||||
}),
|
||||
@@ -160,7 +168,7 @@ export const getImageWidthStyling = (
|
||||
minWidth: 'unset',
|
||||
minHeight: '100%',
|
||||
}),
|
||||
...applyStyles(readingMode === ReadingMode.CONTINUOUS_VERTICAL, {
|
||||
...applyStyles(isContinuousVerticalReadingMode(readingMode), {
|
||||
minWidth: width,
|
||||
minHeight: 'unset',
|
||||
}),
|
||||
|
||||
@@ -15,4 +15,7 @@ export const isReaderWidthEditable = (pageScaleMode: IReaderSettings['pageScaleM
|
||||
[ReaderPageScaleMode.WIDTH, ReaderPageScaleMode.SCREEN].includes(pageScaleMode);
|
||||
|
||||
export const isContinuousReadingMode = (readingMode: IReaderSettings['readingMode']): boolean =>
|
||||
[ReadingMode.CONTINUOUS_VERTICAL, ReadingMode.CONTINUOUS_HORIZONTAL].includes(readingMode);
|
||||
[ReadingMode.CONTINUOUS_VERTICAL, ReadingMode.CONTINUOUS_HORIZONTAL, ReadingMode.WEBTOON].includes(readingMode);
|
||||
|
||||
export const isContinuousVerticalReadingMode = (readingMode: IReaderSettings['readingMode']): boolean =>
|
||||
[ReadingMode.CONTINUOUS_VERTICAL, ReadingMode.WEBTOON].includes(readingMode);
|
||||
|
||||
Reference in New Issue
Block a user