Add button to perform search globally in library
This commit is contained in:
@@ -555,6 +555,7 @@
|
|||||||
"library": {
|
"library": {
|
||||||
"action": {
|
"action": {
|
||||||
"label": {
|
"label": {
|
||||||
|
"search_globally": "Search for \"{{query}}\" globally",
|
||||||
"stop_update": "Stop global update",
|
"stop_update": "Stop global update",
|
||||||
"update_category": "Update category",
|
"update_category": "Update category",
|
||||||
"update_library": "Update library"
|
"update_library": "Update library"
|
||||||
|
|||||||
@@ -106,7 +106,11 @@ export const AppRoutes = {
|
|||||||
},
|
},
|
||||||
searchAll: {
|
searchAll: {
|
||||||
match: 'all/search',
|
match: 'all/search',
|
||||||
path: '/sources/all/search',
|
path: (query?: string | null | undefined) => {
|
||||||
|
const queryParam = query ? `query=${encodeURIComponent(query)}` : '';
|
||||||
|
|
||||||
|
return `/sources/all/search${queryParam ? `?${queryParam}` : ''}`;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ import Chip, { ChipProps } from '@mui/material/Chip';
|
|||||||
import Tab from '@mui/material/Tab';
|
import Tab from '@mui/material/Tab';
|
||||||
import { styled } from '@mui/material/styles';
|
import { styled } from '@mui/material/styles';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useQueryParam, NumberParam } from 'use-query-params';
|
import { useQueryParam, NumberParam, StringParam } from 'use-query-params';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/feedback/EmptyViewAbsoluteCentered.tsx';
|
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/feedback/EmptyViewAbsoluteCentered.tsx';
|
||||||
import { LoadingPlaceholder } from '@/modules/core/components/feedback/LoadingPlaceholder.tsx';
|
import { LoadingPlaceholder } from '@/modules/core/components/feedback/LoadingPlaceholder.tsx';
|
||||||
@@ -43,6 +46,7 @@ import { useMetadataServerSettings } from '@/modules/settings/services/ServerSet
|
|||||||
import { GET_LIBRARY_MANGA_COUNT } from '@/lib/graphql/queries/MangaQuery.ts';
|
import { GET_LIBRARY_MANGA_COUNT } from '@/lib/graphql/queries/MangaQuery.ts';
|
||||||
import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts';
|
import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts';
|
||||||
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
|
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
|
||||||
|
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||||
|
|
||||||
const TitleWithSizeTag = styled('span')({
|
const TitleWithSizeTag = styled('span')({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -84,6 +88,7 @@ export function Library() {
|
|||||||
const librarySize = librarySizeResponse.data?.mangas.totalCount ?? 0;
|
const librarySize = librarySizeResponse.data?.mangas.totalCount ?? 0;
|
||||||
|
|
||||||
const [tabSearchParam, setTabSearchParam] = useQueryParam('tab', NumberParam);
|
const [tabSearchParam, setTabSearchParam] = useQueryParam('tab', NumberParam);
|
||||||
|
const [query] = useQueryParam('query', StringParam);
|
||||||
|
|
||||||
const activeTab: (typeof tabs)[number] | undefined = tabs.find((tab) => tab.id === tabSearchParam) ?? tabs[0];
|
const activeTab: (typeof tabs)[number] | undefined = tabs.find((tab) => tab.id === tabSearchParam) ?? tabs[0];
|
||||||
|
|
||||||
@@ -164,6 +169,22 @@ export function Library() {
|
|||||||
);
|
);
|
||||||
}, [isSelectModeActive, selectedMangas]);
|
}, [isSelectModeActive, selectedMangas]);
|
||||||
|
|
||||||
|
const triggerGlobalSearchButton = useMemo(
|
||||||
|
() => (
|
||||||
|
<Box sx={{ p: 2 }}>
|
||||||
|
<Button
|
||||||
|
size="large"
|
||||||
|
component={Link}
|
||||||
|
to={AppRoutes.sources.childRoutes.searchAll.path(query)}
|
||||||
|
sx={{ textTransform: 'none', width: '100%' }}
|
||||||
|
>
|
||||||
|
{t('library.action.label.search_globally', { query })}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
[query],
|
||||||
|
);
|
||||||
|
|
||||||
useAppTitle(
|
useAppTitle(
|
||||||
<TitleWithSizeTag>
|
<TitleWithSizeTag>
|
||||||
{t('library.title')}
|
{t('library.title')}
|
||||||
@@ -237,6 +258,7 @@ export function Library() {
|
|||||||
if (tabs.length === 1) {
|
if (tabs.length === 1) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{triggerGlobalSearchButton}
|
||||||
<LibraryMangaGrid
|
<LibraryMangaGrid
|
||||||
// the key needs to include filters and query to force a re-render of the virtuoso grid to prevent https://github.com/petyosi/react-virtuoso/issues/1242
|
// the key needs to include filters and query to force a re-render of the virtuoso grid to prevent https://github.com/petyosi/react-virtuoso/issues/1242
|
||||||
key={filterKey}
|
key={filterKey}
|
||||||
@@ -272,6 +294,7 @@ export function Library() {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</TabsMenu>
|
</TabsMenu>
|
||||||
|
{triggerGlobalSearchButton}
|
||||||
{tabs.map((tab) => (
|
{tabs.map((tab) => (
|
||||||
<TabPanel key={tab.order} index={tab.order} currentIndex={activeTab.order}>
|
<TabPanel key={tab.order} index={tab.order} currentIndex={activeTab.order}>
|
||||||
{tab === activeTab && (
|
{tab === activeTab && (
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export function Sources() {
|
|||||||
useAppAction(
|
useAppAction(
|
||||||
<>
|
<>
|
||||||
<CustomTooltip title={t('search.title.global_search')}>
|
<CustomTooltip title={t('search.title.global_search')}>
|
||||||
<IconButton onClick={() => navigate(AppRoutes.sources.childRoutes.searchAll.path)} color="inherit">
|
<IconButton onClick={() => navigate(AppRoutes.sources.childRoutes.searchAll.path())} color="inherit">
|
||||||
<TravelExploreIcon />
|
<TravelExploreIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</CustomTooltip>
|
</CustomTooltip>
|
||||||
|
|||||||
Reference in New Issue
Block a user