Feature/cleanup files (#528)
* Move menu components into new dir * Move chapter components into new dir * Extract menu helper functions * Move "SelectionFAB" to "collection" dir * Move debounce hook to global utils dir * Rename manga "hooks" to "useRefreshManga"
This commit is contained in:
@@ -21,7 +21,7 @@ import { ContinueReadingButton } from '@/components/manga/ContinueReadingButton.
|
|||||||
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
||||||
import { MangaOptionButton } from '@/components/manga/MangaOptionButton.tsx';
|
import { MangaOptionButton } from '@/components/manga/MangaOptionButton.tsx';
|
||||||
import { MangaActionMenuItems, SingleModeProps } from '@/components/manga/MangaActionMenuItems.tsx';
|
import { MangaActionMenuItems, SingleModeProps } from '@/components/manga/MangaActionMenuItems.tsx';
|
||||||
import { Menu } from '@/components/manga/Menu.tsx';
|
import { Menu } from '@/components/menu/Menu.tsx';
|
||||||
|
|
||||||
const BottomGradient = styled('div')({
|
const BottomGradient = styled('div')({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import BookmarkRemove from '@mui/icons-material/BookmarkRemove';
|
import BookmarkRemove from '@mui/icons-material/BookmarkRemove';
|
||||||
import BookmarkAdd from '@mui/icons-material/BookmarkAdd';
|
import BookmarkAdd from '@mui/icons-material/BookmarkAdd';
|
||||||
import DoneAll from '@mui/icons-material/DoneAll';
|
import DoneAll from '@mui/icons-material/DoneAll';
|
||||||
import { t as translate } from 'i18next';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
||||||
import {
|
import {
|
||||||
@@ -27,28 +26,10 @@ import {
|
|||||||
Chapters,
|
Chapters,
|
||||||
} from '@/lib/data/Chapters.ts';
|
} from '@/lib/data/Chapters.ts';
|
||||||
import { TChapter } from '@/typings.ts';
|
import { TChapter } from '@/typings.ts';
|
||||||
import { MenuItem } from '@/components/manga/MenuItem.tsx';
|
import { MenuItem } from '@/components/menu/MenuItem.tsx';
|
||||||
import { IChapterWithMeta } from '@/components/manga/ChapterList.tsx';
|
import { IChapterWithMeta } from '@/components/chapter/ChapterList.tsx';
|
||||||
import { ChaptersWithMeta } from '@/lib/data/ChaptersWithMeta.ts';
|
import { ChaptersWithMeta } from '@/lib/data/ChaptersWithMeta.ts';
|
||||||
|
import { createGetMenuItemTitle, createIsMenuItemDisabled, createShouldShowMenuItem } from '@/components/menu/util.ts';
|
||||||
const createGetMenuItemTitle =
|
|
||||||
(isSingleMode: boolean) =>
|
|
||||||
(action: ChapterAction, count: number): string => {
|
|
||||||
const countSuffix = count > 0 ? ` (${count})` : '';
|
|
||||||
return `${translate(
|
|
||||||
actionToTranslationKey[action].action[isSingleMode ? 'single' : 'selected'],
|
|
||||||
)}${countSuffix}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createShouldShowMenuItem =
|
|
||||||
(isSingleMode: boolean) =>
|
|
||||||
(shouldBeVisible: boolean = false): boolean =>
|
|
||||||
isSingleMode ? shouldBeVisible : true;
|
|
||||||
|
|
||||||
const createIsMenuItemDisabled =
|
|
||||||
(isSingleMode: boolean) =>
|
|
||||||
(shouldBeDisabled: boolean): boolean =>
|
|
||||||
isSingleMode ? false : shouldBeDisabled;
|
|
||||||
|
|
||||||
type BaseProps = { onClose: () => void };
|
type BaseProps = { onClose: () => void };
|
||||||
|
|
||||||
@@ -80,7 +61,7 @@ export const ChapterActionMenuItems = ({
|
|||||||
const isSingleMode = !!chapter;
|
const isSingleMode = !!chapter;
|
||||||
const { isDownloaded, isRead, isBookmarked } = chapter ?? {};
|
const { isDownloaded, isRead, isBookmarked } = chapter ?? {};
|
||||||
|
|
||||||
const getMenuItemTitle = createGetMenuItemTitle(isSingleMode);
|
const getMenuItemTitle = createGetMenuItemTitle(isSingleMode, actionToTranslationKey);
|
||||||
const shouldShowMenuItem = createShouldShowMenuItem(isSingleMode);
|
const shouldShowMenuItem = createShouldShowMenuItem(isSingleMode);
|
||||||
const isMenuItemDisabled = createIsMenuItemDisabled(isSingleMode);
|
const isMenuItemDisabled = createIsMenuItemDisabled(isSingleMode);
|
||||||
|
|
||||||
@@ -18,12 +18,12 @@ import React, { TouchEvent } from 'react';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
|
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
|
||||||
import { getUploadDateString } from '@/util/date';
|
import { getUploadDateString } from '@/util/date.ts';
|
||||||
import { DownloadStateIndicator } from '@/components/molecules/DownloadStateIndicator';
|
import { DownloadStateIndicator } from '@/components/molecules/DownloadStateIndicator.tsx';
|
||||||
import { DownloadType } from '@/lib/graphql/generated/graphql.ts';
|
import { DownloadType } from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { TChapter } from '@/typings.ts';
|
import { TChapter } from '@/typings.ts';
|
||||||
import { ChapterActionMenuItems } from '@/components/manga/ChapterActionMenuItems.tsx';
|
import { ChapterActionMenuItems } from '@/components/chapter/ChapterActionMenuItems.tsx';
|
||||||
import { Menu } from '@/components/manga/Menu.tsx';
|
import { Menu } from '@/components/menu/Menu.tsx';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
chapter: TChapter;
|
chapter: TChapter;
|
||||||
@@ -14,21 +14,21 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import DownloadIcon from '@mui/icons-material/Download';
|
import DownloadIcon from '@mui/icons-material/Download';
|
||||||
import DoneAllIcon from '@mui/icons-material/DoneAll';
|
import DoneAllIcon from '@mui/icons-material/DoneAll';
|
||||||
import { TChapter, TManga } from '@/typings';
|
import { TChapter, TManga } from '@/typings.ts';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { ChapterCard } from '@/components/manga/ChapterCard';
|
import { ChapterCard } from '@/components/chapter/ChapterCard.tsx';
|
||||||
import { ResumeFab } from '@/components/manga/ResumeFAB';
|
import { ResumeFab } from '@/components/manga/ResumeFAB.tsx';
|
||||||
import { filterAndSortChapters, useChapterOptions } from '@/components/manga/util';
|
import { filterAndSortChapters, useChapterOptions } from '@/components/chapter/util.tsx';
|
||||||
import { EmptyView } from '@/components/util/EmptyView';
|
import { EmptyView } from '@/components/util/EmptyView.tsx';
|
||||||
import { ChaptersToolbarMenu } from '@/components/manga/ChaptersToolbarMenu';
|
import { ChaptersToolbarMenu } from '@/components/chapter/ChaptersToolbarMenu.tsx';
|
||||||
import { SelectionFAB } from '@/components/manga/SelectionFAB';
|
import { SelectionFAB } from '@/components/collection/SelectionFAB.tsx';
|
||||||
import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab';
|
import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab.tsx';
|
||||||
import { DownloadType } from '@/lib/graphql/generated/graphql.ts';
|
import { DownloadType } from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { useSelectableCollection } from '@/components/collection/useSelectableCollection.ts';
|
import { useSelectableCollection } from '@/components/collection/useSelectableCollection.ts';
|
||||||
import { SelectableCollectionSelectAll } from '@/components/collection/SelectableCollectionSelectAll.tsx';
|
import { SelectableCollectionSelectAll } from '@/components/collection/SelectableCollectionSelectAll.tsx';
|
||||||
import { Chapters } from '@/lib/data/Chapters.ts';
|
import { Chapters } from '@/lib/data/Chapters.ts';
|
||||||
import { ChaptersWithMeta } from '@/lib/data/ChaptersWithMeta.ts';
|
import { ChaptersWithMeta } from '@/lib/data/ChaptersWithMeta.ts';
|
||||||
import { ChapterActionMenuItems } from '@/components/manga/ChapterActionMenuItems.tsx';
|
import { ChapterActionMenuItems } from '@/components/chapter/ChapterActionMenuItems.tsx';
|
||||||
|
|
||||||
const ChapterListHeader = styled(Stack)(({ theme }) => ({
|
const ChapterListHeader = styled(Stack)(({ theme }) => ({
|
||||||
margin: 8,
|
margin: 8,
|
||||||
@@ -9,12 +9,12 @@
|
|||||||
import { RadioGroup } from '@mui/material';
|
import { RadioGroup } from '@mui/material';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ChapterListOptions, ChapterOptionsReducerAction, TranslationKey } from '@/typings';
|
import { ChapterListOptions, ChapterOptionsReducerAction, TranslationKey } from '@/typings.ts';
|
||||||
import { RadioInput } from '@/components/atoms/RadioInput';
|
import { RadioInput } from '@/components/atoms/RadioInput.tsx';
|
||||||
import { SortRadioInput } from '@/components/atoms/SortRadioInput';
|
import { SortRadioInput } from '@/components/atoms/SortRadioInput.tsx';
|
||||||
import { ThreeStateCheckboxInput } from '@/components/atoms/ThreeStateCheckboxInput';
|
import { ThreeStateCheckboxInput } from '@/components/atoms/ThreeStateCheckboxInput.tsx';
|
||||||
import { OptionsTabs } from '@/components/molecules/OptionsTabs';
|
import { OptionsTabs } from '@/components/molecules/OptionsTabs.tsx';
|
||||||
import { SORT_OPTIONS } from '@/components/manga/util';
|
import { SORT_OPTIONS } from '@/components/chapter/util.tsx';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -10,9 +10,9 @@ import FilterList from '@mui/icons-material/FilterList';
|
|||||||
import { IconButton, Tooltip } from '@mui/material';
|
import { IconButton, Tooltip } from '@mui/material';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ChapterListOptions, ChapterOptionsReducerAction } from '@/typings';
|
import { ChapterListOptions, ChapterOptionsReducerAction } from '@/typings.ts';
|
||||||
import { ChapterOptions } from '@/components/manga/ChapterOptions';
|
import { ChapterOptions } from '@/components/chapter/ChapterOptions.tsx';
|
||||||
import { isFilterActive } from '@/components/manga/util';
|
import { isFilterActive } from '@/components/chapter/util.tsx';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
options: ChapterListOptions;
|
options: ChapterListOptions;
|
||||||
@@ -14,8 +14,8 @@ import {
|
|||||||
NullAndUndefined,
|
NullAndUndefined,
|
||||||
TChapter,
|
TChapter,
|
||||||
TranslationKey,
|
TranslationKey,
|
||||||
} from '@/typings';
|
} from '@/typings.ts';
|
||||||
import { useReducerLocalStorage } from '@/util/useLocalStorage';
|
import { useReducerLocalStorage } from '@/util/useLocalStorage.tsx';
|
||||||
|
|
||||||
const defaultChapterOptions: ChapterListOptions = {
|
const defaultChapterOptions: ChapterListOptions = {
|
||||||
active: false,
|
active: false,
|
||||||
@@ -11,9 +11,9 @@ import { Fab, Box, styled } from '@mui/material';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
|
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
|
||||||
import { DEFAULT_FAB_STYLE } from '@/components/util/StyledFab';
|
import { DEFAULT_FAB_STYLE } from '@/components/util/StyledFab.tsx';
|
||||||
import { TranslationKey } from '@/typings.ts';
|
import { TranslationKey } from '@/typings.ts';
|
||||||
import { Menu } from '@/components/manga/Menu.tsx';
|
import { Menu } from '@/components/menu/Menu.tsx';
|
||||||
|
|
||||||
interface SelectionFABProps {
|
interface SelectionFABProps {
|
||||||
children: (handleClose: () => void, setHideMenu: (hide: boolean) => void) => JSX.Element;
|
children: (handleClose: () => void, setHideMenu: (hide: boolean) => void) => JSX.Element;
|
||||||
@@ -15,34 +15,15 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
|
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
|
||||||
import Label from '@mui/icons-material/Label';
|
import Label from '@mui/icons-material/Label';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { t as translate } from 'i18next';
|
|
||||||
import { TManga } from '@/typings.ts';
|
import { TManga } from '@/typings.ts';
|
||||||
import { actionToTranslationKey, MangaAction, MangaDownloadInfo, Mangas, MangaUnreadInfo } from '@/lib/data/Mangas.ts';
|
import { actionToTranslationKey, MangaAction, MangaDownloadInfo, Mangas, MangaUnreadInfo } from '@/lib/data/Mangas.ts';
|
||||||
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts';
|
||||||
import { CategorySelect } from '@/components/navbar/action/CategorySelect.tsx';
|
import { CategorySelect } from '@/components/navbar/action/CategorySelect.tsx';
|
||||||
import { MenuItem } from '@/components/manga/MenuItem.tsx';
|
import { MenuItem } from '@/components/menu/MenuItem.tsx';
|
||||||
|
import { createGetMenuItemTitle, createIsMenuItemDisabled, createShouldShowMenuItem } from '@/components/menu/util.ts';
|
||||||
|
|
||||||
const ACTION_DISABLES_SELECTION_MODE: MangaAction[] = ['remove_from_library'] as const;
|
const ACTION_DISABLES_SELECTION_MODE: MangaAction[] = ['remove_from_library'] as const;
|
||||||
|
|
||||||
const createGetMenuItemTitle =
|
|
||||||
(isSingleMode: boolean) =>
|
|
||||||
(action: MangaAction, count: number): string => {
|
|
||||||
const countSuffix = count > 0 ? ` (${count})` : '';
|
|
||||||
return `${translate(
|
|
||||||
actionToTranslationKey[action].action[isSingleMode ? 'single' : 'selected'],
|
|
||||||
)}${countSuffix}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createShouldShowMenuItem =
|
|
||||||
(isSingleMode: boolean) =>
|
|
||||||
(shouldBeVisible: boolean = false): boolean =>
|
|
||||||
isSingleMode ? shouldBeVisible : true;
|
|
||||||
|
|
||||||
const createIsMenuItemDisabled =
|
|
||||||
(isSingleMode: boolean) =>
|
|
||||||
(shouldBeDisabled: boolean): boolean =>
|
|
||||||
isSingleMode ? false : shouldBeDisabled;
|
|
||||||
|
|
||||||
type BaseProps = { onClose: (selectionModeState: boolean) => void; setHideMenu: (hide: boolean) => void };
|
type BaseProps = { onClose: (selectionModeState: boolean) => void; setHideMenu: (hide: boolean) => void };
|
||||||
|
|
||||||
export type SingleModeProps = {
|
export type SingleModeProps = {
|
||||||
@@ -65,7 +46,7 @@ export const MangaActionMenuItems = ({ manga, handleSelection, selectedMangas =
|
|||||||
|
|
||||||
const isSingleMode = !!manga;
|
const isSingleMode = !!manga;
|
||||||
|
|
||||||
const getMenuItemTitle = createGetMenuItemTitle(isSingleMode);
|
const getMenuItemTitle = createGetMenuItemTitle(isSingleMode, actionToTranslationKey);
|
||||||
const shouldShowMenuItem = createShouldShowMenuItem(isSingleMode);
|
const shouldShowMenuItem = createShouldShowMenuItem(isSingleMode);
|
||||||
const isMenuItemDisabled = createIsMenuItemDisabled(isSingleMode);
|
const isMenuItemDisabled = createIsMenuItemDisabled(isSingleMode);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
|
|
||||||
export const useRefreshManga = (mangaId: string) => {
|
export const useRefreshManga = (mangaId: string) => {
|
||||||
@@ -22,19 +22,3 @@ export const useRefreshManga = (mangaId: string) => {
|
|||||||
|
|
||||||
return [handleRefresh, { loading: fetchingOnline }] as const;
|
return [handleRefresh, { loading: fetchingOnline }] as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDebounce = <Value>(value: Value, delay: number): Value => {
|
|
||||||
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handler = setTimeout(() => {
|
|
||||||
setDebouncedValue(value);
|
|
||||||
}, delay);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearTimeout(handler);
|
|
||||||
};
|
|
||||||
}, [value, delay]);
|
|
||||||
|
|
||||||
return debouncedValue;
|
|
||||||
};
|
|
||||||
42
src/components/menu/util.ts
Normal file
42
src/components/menu/util.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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 { t as translate } from 'i18next';
|
||||||
|
import { TranslationKey } from '@/typings.ts';
|
||||||
|
|
||||||
|
export const createGetMenuItemTitle =
|
||||||
|
<Action extends string>(
|
||||||
|
isSingleMode: boolean,
|
||||||
|
actionToTranslationKey: Record<
|
||||||
|
Action,
|
||||||
|
{
|
||||||
|
action: {
|
||||||
|
single: TranslationKey;
|
||||||
|
selected: TranslationKey;
|
||||||
|
};
|
||||||
|
success: TranslationKey;
|
||||||
|
error: TranslationKey;
|
||||||
|
}
|
||||||
|
>,
|
||||||
|
) =>
|
||||||
|
(action: Action, count: number): string => {
|
||||||
|
const countSuffix = count > 0 ? ` (${count})` : '';
|
||||||
|
return `${translate(
|
||||||
|
actionToTranslationKey[action].action[isSingleMode ? 'single' : 'selected'],
|
||||||
|
)}${countSuffix}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createShouldShowMenuItem =
|
||||||
|
(isSingleMode: boolean) =>
|
||||||
|
(shouldBeVisible: boolean = false): boolean =>
|
||||||
|
isSingleMode ? shouldBeVisible : true;
|
||||||
|
|
||||||
|
export const createIsMenuItemDisabled =
|
||||||
|
(isSingleMode: boolean) =>
|
||||||
|
(shouldBeDisabled: boolean): boolean =>
|
||||||
|
isSingleMode ? false : shouldBeDisabled;
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
import SearchIcon from '@mui/icons-material/Search';
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
import { FormControl, Input, InputAdornment, InputLabel } from '@mui/material';
|
import { FormControl, Input, InputAdornment, InputLabel } from '@mui/material';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useDebounce } from '@/components/manga/hooks';
|
import { useDebounce } from '@/util/useDebounce.ts';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
state: string;
|
state: string;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { useSelectableCollection } from '@/components/collection/useSelectableCo
|
|||||||
import { TManga } from '@/typings.ts';
|
import { TManga } from '@/typings.ts';
|
||||||
import { SelectableCollectionSelectMode } from '@/components/collection/SelectableCollectionSelectMode.tsx';
|
import { SelectableCollectionSelectMode } from '@/components/collection/SelectableCollectionSelectMode.tsx';
|
||||||
import { useGetVisibleLibraryMangas } from '@/components/library/useGetVisibleLibraryMangas.ts';
|
import { useGetVisibleLibraryMangas } from '@/components/library/useGetVisibleLibraryMangas.ts';
|
||||||
import { SelectionFAB } from '@/components/manga/SelectionFAB.tsx';
|
import { SelectionFAB } from '@/components/collection/SelectionFAB.tsx';
|
||||||
import { PARTIAL_MANGA_FIELDS } from '@/lib/graphql/Fragments.ts';
|
import { PARTIAL_MANGA_FIELDS } from '@/lib/graphql/Fragments.ts';
|
||||||
import { MangaActionMenuItems } from '@/components/manga/MangaActionMenuItems.tsx';
|
import { MangaActionMenuItems } from '@/components/manga/MangaActionMenuItems.tsx';
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import { useParams } from 'react-router-dom';
|
|||||||
import { isNetworkRequestInFlight } from '@apollo/client/core/networkStatus';
|
import { isNetworkRequestInFlight } from '@apollo/client/core/networkStatus';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext';
|
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext';
|
||||||
import { ChapterList } from '@/components/manga/ChapterList';
|
import { ChapterList } from '@/components/chapter/ChapterList.tsx';
|
||||||
import { useRefreshManga } from '@/components/manga/hooks';
|
import { useRefreshManga } from '@/components/manga/useRefreshManga.ts';
|
||||||
import { MangaDetails } from '@/components/manga/MangaDetails';
|
import { MangaDetails } from '@/components/manga/MangaDetails';
|
||||||
import { MangaToolbarMenu } from '@/components/manga/MangaToolbarMenu';
|
import { MangaToolbarMenu } from '@/components/manga/MangaToolbarMenu';
|
||||||
import { EmptyView } from '@/components/util/EmptyView';
|
import { EmptyView } from '@/components/util/EmptyView';
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import { VerticalPager } from '@/components/reader/pager/VerticalPager';
|
|||||||
import { ReaderNavBar } from '@/components/navbar/ReaderNavBar';
|
import { ReaderNavBar } from '@/components/navbar/ReaderNavBar';
|
||||||
import { makeToast } from '@/components/util/Toast';
|
import { makeToast } from '@/components/util/Toast';
|
||||||
import { NavBarContext } from '@/components/context/NavbarContext.tsx';
|
import { NavBarContext } from '@/components/context/NavbarContext.tsx';
|
||||||
import { useDebounce } from '@/components/manga/hooks.ts';
|
import { useDebounce } from '@/util/useDebounce.ts';
|
||||||
import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts';
|
import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { useMetadataServerSettings } from '@/util/metadataServerSettings.ts';
|
import { useMetadataServerSettings } from '@/util/metadataServerSettings.ts';
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { translateExtensionLanguage } from '@/screens/util/Extensions';
|
|||||||
import { AppbarSearch } from '@/components/util/AppbarSearch';
|
import { AppbarSearch } from '@/components/util/AppbarSearch';
|
||||||
import { LangSelect } from '@/components/navbar/action/LangSelect';
|
import { LangSelect } from '@/components/navbar/action/LangSelect';
|
||||||
import { MangaGrid } from '@/components/MangaGrid';
|
import { MangaGrid } from '@/components/MangaGrid';
|
||||||
import { useDebounce } from '@/components/manga/hooks';
|
import { useDebounce } from '@/util/useDebounce.ts';
|
||||||
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext.tsx';
|
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext.tsx';
|
||||||
|
|
||||||
type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean };
|
type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean };
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import {
|
|||||||
AbortableApolloUseMutationPaginatedResponse,
|
AbortableApolloUseMutationPaginatedResponse,
|
||||||
SPECIAL_ED_SOURCES,
|
SPECIAL_ED_SOURCES,
|
||||||
} from '@/lib/requests/RequestManager.ts';
|
} from '@/lib/requests/RequestManager.ts';
|
||||||
import { useDebounce } from '@/components/manga/hooks';
|
import { useDebounce } from '@/util/useDebounce.ts';
|
||||||
import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext';
|
import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext';
|
||||||
import { SourceGridLayout } from '@/components/source/GridLayouts';
|
import { SourceGridLayout } from '@/components/source/GridLayouts';
|
||||||
import { AppbarSearch } from '@/components/util/AppbarSearch';
|
import { AppbarSearch } from '@/components/util/AppbarSearch';
|
||||||
|
|||||||
25
src/util/useDebounce.ts
Normal file
25
src/util/useDebounce.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export const useDebounce = <Value>(value: Value, delay: number): Value => {
|
||||||
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setDebouncedValue(value);
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler);
|
||||||
|
};
|
||||||
|
}, [value, delay]);
|
||||||
|
|
||||||
|
return debouncedValue;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user