diff --git a/src/components/Collection/Filter/FilterSidebar.tsx b/src/components/Collection/Filter/FilterSidebar.tsx index 3496f45a4..a4f166ddb 100644 --- a/src/components/Collection/Filter/FilterSidebar.tsx +++ b/src/components/Collection/Filter/FilterSidebar.tsx @@ -70,7 +70,7 @@ const FilterSidebar = () => { return ( } > diff --git a/src/components/Collection/Group/EditGroupModal.tsx b/src/components/Collection/Group/EditGroupModal.tsx index 76e9064eb..d0fd87333 100644 --- a/src/components/Collection/Group/EditGroupModal.tsx +++ b/src/components/Collection/Group/EditGroupModal.tsx @@ -54,7 +54,7 @@ const EditGroupModal = () => { className={cx( activeTab === key ? 'w-[12rem] text-center bg-panel-menu-item-background p-3 rounded-lg text-panel-menu-item-text cursor-pointer' - : 'w-[12rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer', + : 'w-[12rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer transition-colors', )} key={key} onClick={() => setActiveTab(key)} diff --git a/src/components/Collection/Group/EditGroupTabs/NameTab.tsx b/src/components/Collection/Group/EditGroupTabs/NameTab.tsx index b18218eee..d5f55fa6c 100644 --- a/src/components/Collection/Group/EditGroupTabs/NameTab.tsx +++ b/src/components/Collection/Group/EditGroupTabs/NameTab.tsx @@ -121,7 +121,7 @@ const NameTab = React.memo(({ groupId }: Props) => {
{seriesData?.map(series => (
setGroupName(series.Name)} > diff --git a/src/components/Collection/ListViewItem.tsx b/src/components/Collection/ListViewItem.tsx index c95cf0a9c..cc262e691 100644 --- a/src/components/Collection/ListViewItem.tsx +++ b/src/components/Collection/ListViewItem.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react'; import { useDispatch } from 'react-redux'; -import { Link } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; import { mdiAlertCircleOutline, mdiCalendarMonthOutline, @@ -17,11 +17,14 @@ import { reduce } from 'lodash'; import BackgroundImagePlaceholderDiv from '@/components/BackgroundImagePlaceholderDiv'; import { listItemSize } from '@/components/Collection/constants'; +import Button from '@/components/Input/Button'; import { useSeriesTagsQuery } from '@/core/react-query/series/queries'; import { useSettingsQuery } from '@/core/react-query/settings/queries'; +import { resetFilter, setFilterTag } from '@/core/slices/collection'; import { setGroupId } from '@/core/slices/modals/editGroup'; import { setSeriesId } from '@/core/slices/modals/editSeries'; import { dayjs, formatThousand } from '@/core/util'; +import { addFilterCriteriaToStore } from '@/core/utilities/filter'; import useEventCallback from '@/hooks/useEventCallback'; import useMainPoster from '@/hooks/useMainPoster'; @@ -45,17 +48,29 @@ const renderFileSources = (sources: SeriesSizesFileSourcesType): string => { return output.join(' | '); }; -const SeriesTag = ({ text, type }: { text: string, type: 'AniDB' | 'User' }) => ( -
- - {text} -
-); +const SeriesTag = React.memo(({ text, type }: { text: string, type: 'User' | 'AniDB' }) => { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const handleClick = useEventCallback(() => { + dispatch(resetFilter()); + dispatch(setFilterTag({ HasTag: [{ Name: text, isExcluded: false }] })); + addFilterCriteriaToStore('HasTag').catch(console.error); + navigate('/webui/collection'); + }); + + return ( + + ); +}); type Props = { item: CollectionGroupType | SeriesType; @@ -152,21 +167,18 @@ const ListViewItem = ({ groupExtras, isSeries, isSidebarOpen, item }: Props) =>
-
- -
+ +
{showGroupIndicator && groupCount > 1 && (
@@ -177,7 +189,15 @@ const ListViewItem = ({ groupExtras, isSeries, isSidebarOpen, item }: Props) =>
-
{item.Name}
+
+ + {item.Name} + +
diff --git a/src/components/Collection/PosterViewItem.tsx b/src/components/Collection/PosterViewItem.tsx index 756ec53d4..49ad227fa 100644 --- a/src/components/Collection/PosterViewItem.tsx +++ b/src/components/Collection/PosterViewItem.tsx @@ -6,6 +6,7 @@ import { Icon } from '@mdi/react'; import { reduce } from 'lodash'; import BackgroundImagePlaceholderDiv from '@/components/BackgroundImagePlaceholderDiv'; +import Button from '@/components/Input/Button'; import { useSettingsQuery } from '@/core/react-query/settings/queries'; import { setGroupId } from '@/core/slices/modals/editGroup'; import { setSeriesId } from '@/core/slices/modals/editSeries'; @@ -65,14 +66,14 @@ const PosterViewItem = ({ isSeries = false, item }: Props) => { }); return ( - -
+
+ @@ -84,16 +85,13 @@ const PosterViewItem = ({ isSeries = false, item }: Props) => {
)}
-
- -
+ +
{showGroupIndicator && !isSeries && groupCount > 1 && (
@@ -102,20 +100,28 @@ const PosterViewItem = ({ isSeries = false, item }: Props) => {
)} -
-

{item.Name}

- {showEpisodeCount && ( -

- {episodeCount} -  Episodes -

- )} -
+ +
+

+ + {item.Name} + +

+ {showEpisodeCount && ( +

+ {episodeCount} +  Episodes +

+ )}
- +
); }; diff --git a/src/components/Collection/Series/EditSeriesModal.tsx b/src/components/Collection/Series/EditSeriesModal.tsx index 850235af1..c88db98dc 100644 --- a/src/components/Collection/Series/EditSeriesModal.tsx +++ b/src/components/Collection/Series/EditSeriesModal.tsx @@ -69,7 +69,7 @@ const EditSeriesModal = () => { className={cx( activeTab === key ? 'w-[12rem] text-center bg-panel-menu-item-background p-3 rounded-lg text-panel-menu-item-text cursor-pointer' - : 'w-[12rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer', + : 'w-[12rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer transition-colors', )} key={key} onClick={() => setActiveTab(key)} diff --git a/src/components/Collection/Series/EditSeriesTabs/Action.tsx b/src/components/Collection/Series/EditSeriesTabs/Action.tsx index f7ea48827..94405afd5 100644 --- a/src/components/Collection/Series/EditSeriesTabs/Action.tsx +++ b/src/components/Collection/Series/EditSeriesTabs/Action.tsx @@ -6,7 +6,7 @@ const Action = ( ) => (
{
{seriesData?.AniDB?.Titles.map(title => (
setName(title.Name)} > diff --git a/src/components/Collection/SeriesTopPanel.tsx b/src/components/Collection/SeriesTopPanel.tsx index e98b37d55..52d4eff22 100644 --- a/src/components/Collection/SeriesTopPanel.tsx +++ b/src/components/Collection/SeriesTopPanel.tsx @@ -11,6 +11,7 @@ import BackgroundImagePlaceholderDiv from '@/components/BackgroundImagePlacehold import CleanDescription from '@/components/Collection/CleanDescription'; import SeriesInfo from '@/components/Collection/SeriesInfo'; import SeriesUserStats from '@/components/Collection/SeriesUserStats'; +import Button from '@/components/Input/Button'; import ShokoPanel from '@/components/Panels/ShokoPanel'; import { useSeriesImagesQuery, useSeriesTagsQuery } from '@/core/react-query/series/queries'; import { useSettingsQuery } from '@/core/react-query/settings/queries'; @@ -33,7 +34,7 @@ const SeriesTag = React.memo(({ text, type }: { text: string, type: 'User' | 'An }); return ( -
- {text} -
+ {text} + ); }); diff --git a/src/components/Collection/TimelineSidebar.tsx b/src/components/Collection/TimelineSidebar.tsx index 8a28cf168..e98cde0b3 100644 --- a/src/components/Collection/TimelineSidebar.tsx +++ b/src/components/Collection/TimelineSidebar.tsx @@ -1,9 +1,8 @@ import React from 'react'; import { Link } from 'react-router-dom'; -import { mdiLoading } from '@mdi/js'; -import { Icon } from '@mdi/react'; import BackgroundImagePlaceholderDiv from '@/components/BackgroundImagePlaceholderDiv'; +import ShokoPanel from '@/components/Panels/ShokoPanel'; import { SeriesTypeEnum } from '@/core/types/api/series'; import { dayjs } from '@/core/util'; import useMainPoster from '@/hooks/useMainPoster'; @@ -17,42 +16,44 @@ const TimelineItem = ({ series }: { series: SeriesType }) => { : series.AniDB?.Type; return ( - -
+
+ -
-
- {dayjs(series.AniDB?.AirDate).year()} -  |  -
{seriesType}
-
-
{series.Name}
+ +
+
+ {dayjs(series.AniDB?.AirDate).year()} +  |  +
{seriesType}
+
+
+ + {series.Name} +
- +
); }; const TimelineSidebar = ({ isFetching, series }: { isFetching: boolean, series: SeriesType[] }) => ( -
-
-
Timeline
- {isFetching - ? ( -
- -
- ) - : ( -
- {series.map(item => )} -
- )} -
-
+ + {series.map(item => )} + ); export default TimelineSidebar; diff --git a/src/components/Dashboard/DashboardSettingsModal.tsx b/src/components/Dashboard/DashboardSettingsModal.tsx index 76dff5c7a..827ab5947 100644 --- a/src/components/Dashboard/DashboardSettingsModal.tsx +++ b/src/components/Dashboard/DashboardSettingsModal.tsx @@ -113,7 +113,7 @@ const DashboardSettingsModal = ({ onClose, show }: Props) => { className={cx( activeTab === 'widgets' ? 'w-[12rem] text-center bg-panel-menu-item-background p-3 rounded-lg text-panel-menu-item-text cursor-pointer' - : 'w-[12rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer', + : 'w-[12rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer transition-colors', )} key="widgets" onClick={() => setActiveTab('widgets')} @@ -124,7 +124,7 @@ const DashboardSettingsModal = ({ onClose, show }: Props) => { className={cx( activeTab === 'options' ? 'w-[12rem] text-center bg-panel-menu-item-background p-3 rounded-lg text-panel-menu-item-text cursor-pointer' - : 'w-[12rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer', + : 'w-[12rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer transition-colors', )} key="options" onClick={() => setActiveTab('options')} diff --git a/src/components/Dialogs/ActionsModal.tsx b/src/components/Dialogs/ActionsModal.tsx index 0a6e146d0..9f3c1618b 100644 --- a/src/components/Dialogs/ActionsModal.tsx +++ b/src/components/Dialogs/ActionsModal.tsx @@ -104,7 +104,7 @@ const Action = ({ actionKey, length }: { actionKey: string, length: number }) => return (
5 ? 'mr-4' : '', )} onClick={handleAction} @@ -138,7 +138,7 @@ function ActionsModal({ onClose, show }: Props) { className={cx( activeTab === key ? 'w-[7.5rem] text-center bg-panel-menu-item-background p-3 rounded-lg text-panel-menu-item-text cursor-pointer' - : 'w-[7.5rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer', + : 'w-[7.5rem] text-center p-3 rounded-lg hover:bg-panel-menu-item-background-hover cursor-pointer transition-colors', )} key={key} onClick={() => setActiveTab(key)} diff --git a/src/components/Layout/TopNav.tsx b/src/components/Layout/TopNav.tsx index 5fdfe7691..853677704 100644 --- a/src/components/Layout/TopNav.tsx +++ b/src/components/Layout/TopNav.tsx @@ -167,7 +167,7 @@ function TopNav() { layoutEditMode && 'opacity-65 pointer-events-none', )} > -
+
Shoko diff --git a/src/components/Utilities/ReleaseManagement/Title.tsx b/src/components/Utilities/ReleaseManagement/Title.tsx index 7ea65b9d7..4300cd9fa 100644 --- a/src/components/Utilities/ReleaseManagement/Title.tsx +++ b/src/components/Utilities/ReleaseManagement/Title.tsx @@ -4,7 +4,12 @@ import { mdiChevronRight } from '@mdi/js'; import { Icon } from '@mdi/react'; const TabButton = ({ id, name }: { id: string, name: string }) => ( - (isActive ? 'text-panel-text-primary' : '')}> + (isActive ? 'text-panel-text-primary' : 'hover:text-panel-text-primary transition-colors')} + > {name} ); diff --git a/src/components/Utilities/Unrecognized/Title.tsx b/src/components/Utilities/Unrecognized/Title.tsx index 6d11ea9b1..20caef864 100644 --- a/src/components/Utilities/Unrecognized/Title.tsx +++ b/src/components/Utilities/Unrecognized/Title.tsx @@ -4,7 +4,12 @@ import { mdiChevronRight } from '@mdi/js'; import { Icon } from '@mdi/react'; const TabButton = ({ id, name }: { id: string, name: string }) => ( - (isActive ? 'text-panel-text-primary' : '')}> + (isActive ? 'text-panel-text-primary' : 'hover:text-panel-text-primary transition-colors')} + > {name} ); diff --git a/src/pages/collection/Collection.tsx b/src/pages/collection/Collection.tsx index b2ea93a19..e018a598d 100644 --- a/src/pages/collection/Collection.tsx +++ b/src/pages/collection/Collection.tsx @@ -198,7 +198,7 @@ function Collection() { return (
-
+
diff --git a/src/pages/dashboard/panels/CollectionStats.tsx b/src/pages/dashboard/panels/CollectionStats.tsx index 1540a519f..e31e079c4 100644 --- a/src/pages/dashboard/panels/CollectionStats.tsx +++ b/src/pages/dashboard/panels/CollectionStats.tsx @@ -1,23 +1,49 @@ import React from 'react'; -import { useSelector } from 'react-redux'; -import { Link } from 'react-router-dom'; +import { useDispatch, useSelector } from 'react-redux'; +import { Link, useNavigate } from 'react-router-dom'; import prettyBytes from 'pretty-bytes'; import ShokoPanel from '@/components/Panels/ShokoPanel'; import { useDashbordStatsQuery } from '@/core/react-query/dashboard/queries'; +import { resetFilter } from '@/core/slices/collection'; +import { addFilterCriteriaToStore } from '@/core/utilities/filter'; +import useEventCallback from '@/hooks/useEventCallback'; import type { RootState } from '@/core/store'; const Item = ( - { link, title, value = 0 }: { title: string, value?: string | number, link?: string }, -) => ( -
-
- {title} + { filter, link, title, value = 0 }: { title: string, value?: string | number, link?: string, filter?: string }, +) => { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const handleMissingFilter = useEventCallback((filterName: string) => { + dispatch(resetFilter()); + addFilterCriteriaToStore(filterName).then(() => { + navigate('/webui/collection'); + }).catch(console.error); + }); + + return ( +
+
+ {title} +
+ {/* eslint-disable-next-line no-nested-ternary */} + {link + ? {value} + : filter + ? ( +
handleMissingFilter(filter)} + > + {value} +
+ ) + :
{value}
}
- {link ? {value} :
{value}
} -
-); + ); +}; function CollectionStats() { const layoutEditMode = useSelector((state: RootState) => state.mainpage.layoutEditMode); @@ -53,13 +79,24 @@ function CollectionStats() { ]; const childrenThird = [ - , + , , + , - , ]; return ( diff --git a/src/pages/settings/SettingsPage.tsx b/src/pages/settings/SettingsPage.tsx index e4924015e..f8cf9526f 100644 --- a/src/pages/settings/SettingsPage.tsx +++ b/src/pages/settings/SettingsPage.tsx @@ -159,7 +159,7 @@ function SettingsPage() { to={item.path} className={({ isActive }) => (isActive ? 'w-full text-center bg-panel-menu-item-background py-2 px-2 rounded-lg text-panel-menu-item-text' - : 'w-full text-center py-2 px-2 rounded-lg hover:bg-panel-menu-item-background-hover')} + : 'w-full text-center py-2 px-2 rounded-lg hover:bg-panel-menu-item-background-hover transition-colors')} key={item.path} > {item.name}