From 79b2305e540fa85346d47b598d05bd12004b3742 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 22 Apr 2023 11:39:59 +0200 Subject: [PATCH] Feature/library show number of mangas in category (#269) * Pass optional browser tab only title Makes it possible to have a different title for the "NavBar" and the browser tab * Show number of items in category and library --------- Co-authored-by: schroda --- .../context/LibraryOptionsContext.tsx | 2 + src/components/context/NavbarContext.tsx | 4 +- .../library/LibraryOptionsPanel.tsx | 9 ++++- .../navbar/NavBarContextProvider.tsx | 6 +-- src/i18n/locale/en.json | 6 +++ src/screens/Library.tsx | 40 ++++++++++++++++--- src/typings.ts | 2 + 7 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/components/context/LibraryOptionsContext.tsx b/src/components/context/LibraryOptionsContext.tsx index a6d80371..caaece64 100644 --- a/src/components/context/LibraryOptionsContext.tsx +++ b/src/components/context/LibraryOptionsContext.tsx @@ -29,6 +29,8 @@ export const DefaultLibraryOptions: LibraryOptions = { sortDesc: undefined, sorts: undefined, unread: undefined, + + showTabSize: false, }; const LibraryOptionsContext = React.createContext({ diff --git a/src/components/context/NavbarContext.tsx b/src/components/context/NavbarContext.tsx index fd1701f1..54be9de5 100644 --- a/src/components/context/NavbarContext.tsx +++ b/src/components/context/NavbarContext.tsx @@ -14,8 +14,8 @@ type ContextType = { setDefaultBackTo: React.Dispatch>; // AppBar title - title: string; - setTitle: (title: string) => void; + title: string | React.ReactNode; + setTitle: (title: ContextType['title'], browserTitle?: string) => void; // AppBar action buttons action: any; diff --git a/src/components/library/LibraryOptionsPanel.tsx b/src/components/library/LibraryOptionsPanel.tsx index 1433af78..192d7c50 100644 --- a/src/components/library/LibraryOptionsPanel.tsx +++ b/src/components/library/LibraryOptionsPanel.tsx @@ -81,7 +81,7 @@ const LibraryOptionsPanel: React.FC = ({ open, onClose }) => { )); } if (key === 'display') { - const { gridLayout, showDownloadBadge, showUnreadBadge } = options; + const { gridLayout, showDownloadBadge, showUnreadBadge, showTabSize } = options; return ( <> {t('global.grid_layout.title')} @@ -117,6 +117,13 @@ const LibraryOptionsPanel: React.FC = ({ open, onClose }) => { checked={showDownloadBadge === true} onChange={() => handleFilterChange('showDownloadBadge', !showDownloadBadge)} /> + + {t('library.option.display.tab.title')} + handleFilterChange('showTabSize', !showTabSize)} + /> ); } diff --git a/src/components/navbar/NavBarContextProvider.tsx b/src/components/navbar/NavBarContextProvider.tsx index b5a149ab..e4c61b38 100644 --- a/src/components/navbar/NavBarContextProvider.tsx +++ b/src/components/navbar/NavBarContextProvider.tsx @@ -15,7 +15,7 @@ interface IProps { export default function NavBarProvider({ children }: IProps) { const [defaultBackTo, setDefaultBackTo] = useState(); - const [title, setTitle] = useState('Tachidesk'); + const [title, setTitle] = useState('Tachidesk'); const [action, setAction] = useState(
); const [override, setOverride] = useState({ status: false, @@ -23,8 +23,8 @@ export default function NavBarProvider({ children }: IProps) { }); const updateTitle = useCallback( - (newTitle: string) => { - document.title = `${newTitle} - Tachidesk`; + (newTitle: string | React.ReactNode, browserTitle: string = typeof newTitle === 'string' ? newTitle : '') => { + document.title = `${browserTitle} - Tachidesk`; setTitle(newTitle); }, [setTitle], diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 5fdaf751..a97e2dd6 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -268,6 +268,12 @@ "unread_badges": "Unread Badges" }, "title": "Badges" + }, + "tab": { + "title": "Tabs", + "label": { + "show_number_of_items": "Show number of items" + } } }, "sort": { diff --git a/src/screens/Library.tsx b/src/screens/Library.tsx index 5d433026..9b9775a2 100644 --- a/src/screens/Library.tsx +++ b/src/screens/Library.tsx @@ -5,8 +5,8 @@ * 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 { Tab, Tabs } from '@mui/material'; -import React, { useContext, useEffect, useState } from 'react'; +import { Chip, Tab, Tabs } from '@mui/material'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import NavbarContext from 'components/context/NavbarContext'; import EmptyView from 'components/util/EmptyView'; import LoadingPlaceholder from 'components/util/LoadingPlaceholder'; @@ -19,13 +19,26 @@ import { useQuery } from 'util/client'; import UpdateChecker from 'components/library/UpdateChecker'; import { useTranslation } from 'react-i18next'; import { ICategory, IManga } from 'typings'; +import { styled } from '@mui/system'; +import { useLibraryOptionsContext } from 'components/context/LibraryOptionsContext'; + +const TitleWithSizeTag = styled('span')({ + display: 'flex', + alignItems: 'center', +}); + +const TitleSizeTag = (props: React.ComponentProps) => ( + +); export default function Library() { const { t } = useTranslation(); + const { options } = useLibraryOptionsContext(); const [lastLibraryUpdate, setLastLibraryUpdate] = useState(Date.now()); const { data: tabsData, error: tabsError, loading } = useQuery('/api/v1/category'); const tabs = tabsData ?? []; + const librarySize = useMemo(() => tabs.map((tab) => tab.size).reduce((prev, curr) => prev + curr, 0), [tabs]); const [tabSearchParam, setTabSearchParam] = useQueryParam('tab', NumberParam); @@ -41,7 +54,14 @@ export default function Library() { const { setTitle, setAction } = useContext(NavbarContext); useEffect(() => { - setTitle(t('library.title')); + const title = t('library.title'); + const navBarTitle = ( + + {title} + {mangaLoading || !options.showTabSize ? null : } + + ); + setTitle(navBarTitle, title); setAction( <> @@ -53,7 +73,7 @@ export default function Library() { setTitle(''); setAction(null); }; - }, [t]); + }, [t, librarySize, mangaLoading, options]); const handleTabChange = (newTab: number) => { setTabSearchParam(newTab === 0 ? undefined : newTab); @@ -104,7 +124,17 @@ export default function Library() { allowScrollButtonsMobile > {tabs.map((tab) => ( - + + {tab.name} + {options.showTabSize ? : null} + + } + value={tab.order} + /> ))} {tabs.map((tab) => ( diff --git a/src/typings.ts b/src/typings.ts index 02eb2bec..01d3e7bc 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -179,6 +179,7 @@ export interface ICategory { name: string; default: boolean; meta: Metadata; + size: number; } export interface INavbarOverride { @@ -361,6 +362,7 @@ export interface LibraryOptions { unread: NullAndUndefined; sorts: NullAndUndefined; sortDesc: NullAndUndefined; + showTabSize: boolean; } export interface BatchChaptersChange {