diff --git a/src/modules/library/hooks/useGetVisibleLibraryMangas.ts b/src/modules/library/hooks/useGetVisibleLibraryMangas.ts index ec621a3d..ae73cdfb 100644 --- a/src/modules/library/hooks/useGetVisibleLibraryMangas.ts +++ b/src/modules/library/hooks/useGetVisibleLibraryMangas.ts @@ -15,7 +15,13 @@ import { useGetCategoryMetadata } from '@/modules/category/services/CategoryMeta import { NullAndUndefined } from '@/Base.types.ts'; import { LibraryOptions, LibrarySortMode } from '@/modules/library/Library.types.ts'; import { CategoryIdInfo, CategoryMetadataInfo } from '@/modules/category/Category.types.ts'; -import { MangaChapterCountInfo, MangaIdInfo } from '@/modules/manga/Manga.types.ts'; +import { + MangaChapterCountInfo, + MangaDownloadInfo, + MangaIdInfo, + MangaStatusInfo, + MangaUnreadInfo, +} from '@/modules/manga/Manga.types.ts'; import { SourceDisplayNameInfo } from '@/modules/source/Source.types.ts'; const triStateFilter = ( @@ -96,8 +102,7 @@ const trackerFilter = (trackFilters: LibraryOptions['hasTrackerBinding'], manga: }) .every(Boolean); -type TMangaStatusFilter = Pick; -const statusFilter = (statusFilters: LibraryOptions['hasStatus'], manga: TMangaStatusFilter): boolean => +const statusFilter = (statusFilters: LibraryOptions['hasStatus'], manga: MangaStatusInfo): boolean => Object.entries(statusFilters) .map(([status, statusFilterState]) => triStateFilterBoolean(statusFilterState, status === manga.status)) .every(Boolean); @@ -112,10 +117,12 @@ type TMangaFilterOptions = Pick< | 'hasTrackerBinding' | 'hasStatus' >; -type TMangaFilter = Pick & +type TMangaFilter = Pick & TMangaTrackerFilter & - TMangaStatusFilter & - MangaChapterCountInfo; + MangaStatusInfo & + MangaChapterCountInfo & + MangaDownloadInfo & + MangaUnreadInfo; const filterManga = ( manga: TMangaFilter, { diff --git a/src/modules/manga/Manga.types.ts b/src/modules/manga/Manga.types.ts index cbbc30f6..ab04e52f 100644 --- a/src/modules/manga/Manga.types.ts +++ b/src/modules/manga/Manga.types.ts @@ -33,6 +33,7 @@ type MangaCardBaseProps = Pick & export type MangaIdInfo = Pick; export type MangaChapterCountInfo = { chapters: Pick }; +export type MangaInLibraryInfo = Pick; export type MangaDownloadInfo = Pick & MangaChapterCountInfo; export type MangaUnreadInfo = Pick & MangaChapterCountInfo; export type MangaThumbnailInfo = Pick; @@ -40,10 +41,14 @@ export type MangaTrackRecordInfo = MangaIdInfo & { trackRecords: { nodes: Pick[] }; }; export type MangaGenreInfo = Pick; +export type MangaSourceIdInfo = Pick; export type MangaSourceNameInfo = { source?: Maybe> }; export type MangaSourceLngInfo = { source?: Maybe> }; export type MangaArtistInfo = Pick; export type MangaAuthorInfo = Pick; +export type MangaTitleInfo = Pick; +export type MangaDescriptionInfo = Pick; +export type MangaStatusInfo = Pick; export type MigrateMode = 'copy' | 'migrate'; @@ -92,3 +97,8 @@ export enum MangaType { MANHWA, MANHUA, } + +export interface MangaLocationState { + mangaTitle: string; + mode: MangaCardMode | undefined; +} diff --git a/src/modules/manga/components/MangaDetails.tsx b/src/modules/manga/components/MangaDetails.tsx index dbcda37d..a2eff9d9 100644 --- a/src/modules/manga/components/MangaDetails.tsx +++ b/src/modules/manga/components/MangaDetails.tsx @@ -44,12 +44,26 @@ import { useLocalStorage } from '@/modules/core/hooks/useStorage.tsx'; import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx'; import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts'; import { MANGA_COVER_ASPECT_RATIO, MANGA_STATUS_TO_TRANSLATION } from '@/modules/manga/Manga.constants.ts'; -import { MangaThumbnailInfo, MangaTrackRecordInfo } from '@/modules/manga/Manga.types.ts'; +import { + MangaArtistInfo, + MangaAuthorInfo, + MangaDescriptionInfo, + MangaGenreInfo, + MangaIdInfo, + MangaInLibraryInfo, + MangaLocationState, + MangaSourceIdInfo, + MangaStatusInfo, + MangaThumbnailInfo, + MangaTitleInfo, + MangaTrackRecordInfo, +} from '@/modules/manga/Manga.types.ts'; import { TAppThemeContext, useAppThemeContext } from '@/modules/theme/contexts/AppThemeContext.tsx'; import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts'; import { CustomButtonIcon } from '@/modules/core/components/buttons/CustomButtonIcon.tsx'; import { Sources } from '@/modules/source/services/Sources.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; +import { SourceIdInfo } from '@/modules/source/Source.types.ts'; const DetailsWrapper = styled('div')(({ theme }) => ({ display: 'flex', @@ -163,19 +177,40 @@ function getSourceName(source?: Pick | null): return source.displayName ?? source.id; } -const LibrarySearchLink = ({ query, children }: { query: string; children?: ReactNode }) => ( - - {children ?? query} - -); +const SearchLink = ({ + query, + sourceId, + mode, + children, +}: { + query: string; + sourceId: SourceIdInfo['id'] | undefined; + mode: MangaLocationState['mode']; + children?: ReactNode; +}) => { + const link = (() => { + const isSourceMode = mode === 'source' && sourceId !== undefined; + if (isSourceMode) { + return AppRoutes.sources.childRoutes.browse.path(sourceId, query); + } -const valuesToJoinedLibrarySearchLinks = (values: string[] | undefined) => + return AppRoutes.library.path(undefined, query); + })(); + + return ( + + {children ?? query} + + ); +}; + +const valuesToJoinedSearchLinks = ( + values: string[] | undefined, + sourceId: SourceIdInfo['id'] | undefined, + mode: MangaLocationState['mode'], +) => values - ?.map((value) => ) + ?.map((value) => ) .reduce((acc, valueLink) => ( <> {acc}, {valueLink} @@ -310,9 +345,11 @@ const Thumbnail = ({ const OPEN_CLOSE_BUTTON_HEIGHT = '35px'; const DESCRIPTION_COLLAPSED_SIZE = 75; const DescriptionGenre = ({ - manga: { description, genre: mangaGenres }, + manga: { description, genre: mangaGenres, sourceId }, + mode, }: { - manga: Pick; + manga: MangaDescriptionInfo & MangaGenreInfo & MangaSourceIdInfo; + mode: MangaLocationState['mode']; }) => { const [descriptionElement, setDescriptionElement] = useState(null); const [descriptionHeight, setDescriptionHeight] = useState(); @@ -374,9 +411,9 @@ const DescriptionGenre = ({ }} > {genres.map((genre) => ( - + {}} /> - + ))} @@ -385,15 +422,23 @@ const DescriptionGenre = ({ export const MangaDetails = ({ manga, + mode, }: { - manga: Pick< - MangaType, - 'id' | 'title' | 'author' | 'artist' | 'status' | 'inLibrary' | 'realUrl' | 'description' | 'genre' - > & + manga: Pick & + MangaIdInfo & + MangaTitleInfo & + MangaStatusInfo & + MangaInLibraryInfo & + MangaAuthorInfo & + MangaArtistInfo & + MangaDescriptionInfo & + MangaGenreInfo & MangaThumbnailInfo & + MangaSourceIdInfo & MangaTrackRecordInfo & { source?: Pick | null; }; + mode: MangaLocationState['mode']; }) => { const { t } = useTranslation(); @@ -438,13 +483,13 @@ export const MangaDetails = ({ {manga.author && ( )} {manga.artist && ( )} - + {CategorySelectComponent} diff --git a/src/modules/manga/components/cards/MangaGridCard.tsx b/src/modules/manga/components/cards/MangaGridCard.tsx index 7a207d65..d1cdfb47 100644 --- a/src/modules/manga/components/cards/MangaGridCard.tsx +++ b/src/modules/manga/components/cards/MangaGridCard.tsx @@ -65,7 +65,7 @@ export const MangaGridCard = memo( {...longPressBind(() => popupState.open(optionButtonRef.current))} onClick={handleClick} to={mangaLinkTo} - state={{ mangaTitle: title }} + state={Mangas.createLocationState(manga, mode)} sx={{ textDecoration: 'none', touchCallout: 'none' }} > popupState.open(optionButtonRef.current))} sx={{ diff --git a/src/modules/manga/screens/Manga.tsx b/src/modules/manga/screens/Manga.tsx index 807ddade..707a6168 100644 --- a/src/modules/manga/screens/Manga.tsx +++ b/src/modules/manga/screens/Manga.tsx @@ -13,7 +13,7 @@ import Stack from '@mui/material/Stack'; import Box from '@mui/material/Box'; import React, { useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; -import { useParams } from 'react-router-dom'; +import { useLocation, useParams } from 'react-router-dom'; import { isNetworkRequestInFlight } from '@apollo/client/core/networkStatus'; import { CustomTooltip } from '@/modules/core/components/CustomTooltip.tsx'; import { requestManager } from '@/lib/requests/RequestManager.ts'; @@ -27,11 +27,13 @@ import { GetMangaScreenQuery } from '@/lib/graphql/generated/graphql.ts'; import { GET_MANGA_SCREEN } from '@/lib/graphql/queries/MangaQuery.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useAppTitleAndAction } from '@/modules/navigation-bar/hooks/useAppTitleAndAction.ts'; +import { MangaLocationState } from '@/modules/manga/Manga.types.ts'; export const Manga: React.FC = () => { const { t } = useTranslation(); - const { id } = useParams<{ id: string }>(); + const { mode } = useLocation().state ?? {}; + const autofetchedRef = useRef(false); const { @@ -103,7 +105,7 @@ export const Manga: React.FC = () => { {isLoading && } - {manga && } + {manga && } {manga && } ); diff --git a/src/modules/manga/services/Mangas.ts b/src/modules/manga/services/Mangas.ts index 4ed87220..e99a2533 100644 --- a/src/modules/manga/services/Mangas.ts +++ b/src/modules/manga/services/Mangas.ts @@ -29,12 +29,15 @@ import { MangaAction, MangaArtistInfo, MangaAuthorInfo, + MangaCardMode, MangaDownloadInfo, MangaGenreInfo, MangaIdInfo, + MangaLocationState, MangaSourceLngInfo, MangaSourceNameInfo, MangaThumbnailInfo, + MangaTitleInfo, MangaType, MangaUnreadInfo, MigrateMode, @@ -604,4 +607,14 @@ export class Mangas { static getAuthors(manga: Manga): string[] | undefined { return manga.author?.split(ARTIST_AUTHOR_SEPARATOR_REGEX); } + + static createLocationState( + manga: Manga, + mode: MangaCardMode | undefined, + ): MangaLocationState { + return { + mangaTitle: manga.title, + mode, + }; + } }