Trigger library search on artist/author click (#939)

* add search func

* Fix lint issues and clean up

---------

Co-authored-by: schroda <50052685+schroda@users.noreply.github.com>
This commit is contained in:
Well404
2025-05-18 01:04:16 +08:00
committed by GitHub
parent 05dc05a043
commit caad353bfa
8 changed files with 57 additions and 8 deletions

View File

@@ -129,7 +129,7 @@ const MainApp = () => {
<ErrorBoundary>
<Routes>
{/* General Routes */}
<Route path={AppRoutes.root.match} element={<Navigate to={AppRoutes.library.path} replace />} />
<Route path={AppRoutes.root.match} element={<Navigate to={AppRoutes.library.path()} replace />} />
<Route path={AppRoutes.matchAll.match} element={<Navigate to={AppRoutes.root.path} replace />} />
{isMobileWidth && <Route path={AppRoutes.more.match} element={<More />} />}
<Route path={AppRoutes.about.match} element={<About />} />

View File

@@ -128,7 +128,14 @@ export const AppRoutes = {
},
library: {
match: 'library',
path: '/library',
path: (tab?: string, search?: string) => {
const tabParam = tab ? `tab=${tab}` : '';
const searchParam = search ? `query=${encodeURIComponent(search)}` : '';
const params = [tabParam, searchParam].filter(Boolean).join('&');
return `/library${params ? `?${params}` : ''}`;
},
},
updates: {
match: 'updates',

View File

@@ -8,6 +8,7 @@
import Stack, { StackProps } from '@mui/material/Stack';
import Typography, { TypographyProps } from '@mui/material/Typography';
import { ReactNode } from 'react';
export const Metadata = ({
title,
@@ -17,7 +18,7 @@ export const Metadata = ({
valueProps,
}: {
title: string;
value: string;
value: ReactNode;
stackProps?: StackProps;
titleProps?: TypographyProps;
valueProps?: TypographyProps;

View File

@@ -29,6 +29,6 @@ export const useBackButton = () => {
return;
}
navigate(AppRoutes.library.path);
navigate(AppRoutes.library.path());
}, [history, location.pathname]);
};

View File

@@ -42,6 +42,8 @@ export type MangaTrackRecordInfo = MangaIdInfo & {
export type MangaGenreInfo = Pick<MangaTypeGql, 'genre'>;
export type MangaSourceNameInfo = { source?: Maybe<Pick<SourceType, 'name'>> };
export type MangaSourceLngInfo = { source?: Maybe<Pick<SourceType, 'lang'>> };
export type MangaArtistInfo = Pick<MangaTypeGql, 'artist'>;
export type MangaAuthorInfo = Pick<MangaTypeGql, 'author'>;
export type MigrateMode = 'copy' | 'migrate';

View File

@@ -29,6 +29,7 @@ import { Vibrant } from 'node-vibrant/browser';
import { FastAverageColor } from 'fast-average-color';
import parseHtml from 'html-react-parser';
import sanitizeHtml from 'sanitize-html';
import { Link as RouterLink } from 'react-router-dom';
import { CustomTooltip } from '@/modules/core/components/CustomTooltip.tsx';
import { makeToast } from '@/modules/core/utils/Toast.ts';
import { Mangas } from '@/modules/manga/services/Mangas.ts';
@@ -48,6 +49,7 @@ import { TAppThemeContext, useAppThemeContext } from '@/modules/theme/contexts/A
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';
const DetailsWrapper = styled('div')(({ theme }) => ({
display: 'flex',
@@ -161,10 +163,29 @@ function getSourceName(source?: Pick<SourceType, 'id' | 'displayName'> | null):
return source.displayName ?? source.id;
}
function getValueOrUnknown(val?: string | null) {
function getValueOrUnknown<T>(val?: T | null): T | string {
return val ?? translate('global.label.unknown');
}
const LibrarySearchLink = ({ query }: { query: string }) => (
<Link
component={RouterLink}
to={AppRoutes.library.path(undefined, query)}
sx={{ textDecoration: 'none', color: 'inherit' }}
>
{query}
</Link>
);
const valuesToJoinedLibrarySearchLinks = (values: string[] | undefined) =>
values
?.map((value) => <LibrarySearchLink query={value} />)
.reduce((acc, valueLink) => (
<>
{acc}, {valueLink}
</>
));
const Thumbnail = ({
manga,
mangaDynamicColorSchemes,
@@ -416,8 +437,14 @@ export const MangaDetails = ({
</IconButton>
</CustomTooltip>
</Stack>
<Metadata title={t('manga.label.author')} value={getValueOrUnknown(manga.author)} />
<Metadata title={t('manga.label.artist')} value={getValueOrUnknown(manga.artist)} />
<Metadata
title={t('manga.label.author')}
value={getValueOrUnknown(valuesToJoinedLibrarySearchLinks(Mangas.getAuthors(manga)))}
/>
<Metadata
title={t('manga.label.author')}
value={getValueOrUnknown(valuesToJoinedLibrarySearchLinks(Mangas.getArtists(manga)))}
/>
<Metadata
title={t('manga.label.status')}
value={t(MANGA_STATUS_TO_TRANSLATION[manga.status])}

View File

@@ -27,6 +27,8 @@ import { MANGA_BASE_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts';
import { MetadataMigrationSettings } from '@/modules/migration/Migration.types.ts';
import {
MangaAction,
MangaArtistInfo,
MangaAuthorInfo,
MangaDownloadInfo,
MangaGenreInfo,
MangaIdInfo,
@@ -92,6 +94,8 @@ type PerformActionOptions<Action extends MangaAction> = Action extends 'mark_as_
type MigrateFuncReturn = { copy: () => Promise<unknown>[]; cleanup: () => Promise<unknown>[] };
const ARTIST_AUTHOR_SEPARATOR_REGEX = /\s*[,|、]\s*/;
export class Mangas {
static getIds(mangas: MangaIdInfo[]): number[] {
return mangas.map((manga) => manga.id);
@@ -592,4 +596,12 @@ export class Mangas {
Mangas.isType(manga, MangaType.MANHUA)
);
}
static getArtists<Manga extends MangaArtistInfo>(manga: Manga): string[] | undefined {
return manga.artist?.split(ARTIST_AUTHOR_SEPARATOR_REGEX);
}
static getAuthors<Manga extends MangaAuthorInfo>(manga: Manga): string[] | undefined {
return manga.author?.split(ARTIST_AUTHOR_SEPARATOR_REGEX);
}
}

View File

@@ -26,7 +26,7 @@ type RestrictedNavBarItem<Show extends NavbarItem['show']> = Omit<NavbarItem, 's
const NAVIGATION_BAR_BASE_ITEMS = [
{
path: AppRoutes.library.path,
path: AppRoutes.library.path() as RestrictedNavBarItem<'both'>['path'],
title: 'library.title',
SelectedIconComponent: CollectionsBookmarkIcon,
IconComponent: CollectionsOutlinedBookmarkIcon,