Skip to content

Commit

Permalink
Add: Dashboard Missing Ep+Tmdb Link Shortcuts / Collection Tag Links …
Browse files Browse the repository at this point in the history
…and Sticky Searchbar+Sidebars (#1093)

* Collection List View Size / Edit Button Tweak

- give the hover edit button a tooltip to match the ones with the same style on the series page
- make the list view posters slightly larger to stop the two column layout from having slightly different sizes depending on how much text is in the description

* Make Collection List View Tags Clickable

- add the same behavior as the ones on the series page
- this will open the edit tag condition modal which seems like a bonus
- add a tooltip to the tags so the user knows what clicking it does

* Add Missing Episode/TMDB Link Filter Shortcuts to the Dashboard

* Make Collection Searchbar and Sidebars Sticky

- slightly reduced top nav vertical padding
- converted the timeline sidebar into a ShokoPanel like the filter one (for scrolling)

* Make Sidebar Height Important / Don't Clear Filters

- seems more user friendly to keep the non tag filters in case an entire filter stack is overwritten

* Adjust Sidebar Size

- allows for a four instead of three column poster layout with a 1440px window width and the sidebars open
- also makes the sidebar panel gap match the series page/dashboard as it was larger before

* Don't Open the Edit Condition Modal When Initially Clicking Tag Links

* Add Hover to Unrecognized Utility Page Tabs

* Add More Missing Hover Transitions

- added missing hover transitions across the webui
- changed the timeline panel slightly so the poster has the same hover transition/zoom as posters elsewhere
- also make the timeline link only active when hovering the poster so the text can be selected
- changed link state variable name for taglinks

* Apply Review Suggestions

- also remove pointless transition all for ratings

* Add Links to List View and Timeline Titles

- change poster view behavior to match
- add missing edit group hover transition

* Add Hover Title to Timeline

- also move the title from the parent to the link itself for the collection poster/list views
  • Loading branch information
natyusha authored Oct 8, 2024
1 parent 44e1f1a commit 0d64c98
Show file tree
Hide file tree
Showing 18 changed files with 182 additions and 107 deletions.
2 changes: 1 addition & 1 deletion src/components/Collection/Filter/FilterSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const FilterSidebar = () => {
return (
<ShokoPanel
title="Filter"
className="ml-8 w-full"
className="sticky top-24 ml-6 !h-[calc(100vh-18rem)] w-full"
contentClassName="gap-y-6"
options={<Options showModal={showCriteriaModal(true)} />}
>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Collection/Group/EditGroupModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Collection/Group/EditGroupTabs/NameTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ const NameTab = React.memo(({ groupId }: Props) => {
<div className="shoko-scrollbar flex grow flex-col gap-y-2 overflow-y-auto bg-panel-input pr-4">
{seriesData?.map(series => (
<div
className="flex justify-between last:border-none hover:text-panel-text-primary"
className="flex justify-between transition-colors last:border-none hover:text-panel-text-primary"
key={series.IDs.ID}
onClick={() => setGroupName(series.Name)}
>
Expand Down
62 changes: 41 additions & 21 deletions src/components/Collection/ListViewItem.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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';

Expand All @@ -45,17 +48,29 @@ const renderFileSources = (sources: SeriesSizesFileSourcesType): string => {
return output.join(' | ');
};

const SeriesTag = ({ text, type }: { text: string, type: 'AniDB' | 'User' }) => (
<div
className={cx(
'text-xs font-semibold flex gap-x-2 items-center border-2 border-panel-tags rounded-lg p-2 whitespace-nowrap capitalize',
type === 'User' ? 'text-panel-text-important' : 'text-panel-text-primary',
)}
>
<Icon path={mdiTagTextOutline} size="1rem" />
<span className="text-panel-text">{text}</span>
</div>
);
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 (
<Button
className={cx(
'pointer-events-auto text-xs font-semibold flex gap-x-2 items-center border-2 border-panel-tags rounded-lg p-2 whitespace-nowrap capitalize cursor-pointer',
type === 'User' ? 'text-panel-text-important' : 'text-panel-text-primary',
)}
onClick={handleClick}
>
<Icon path={mdiTagTextOutline} size="1rem" />
<span className="text-panel-text transition-colors hover:text-panel-text-primary">{text}</span>
</Button>
);
});

type Props = {
item: CollectionGroupType | SeriesType;
Expand Down Expand Up @@ -152,21 +167,18 @@ const ListViewItem = ({ groupExtras, isSeries, isSidebarOpen, item }: Props) =>
<Link to={viewRouteLink()}>
<BackgroundImagePlaceholderDiv
image={poster}
className="group h-[12.5625rem] w-[8.625rem] shrink-0 rounded-lg drop-shadow-md"
className="group h-[13.438rem] w-[9.25rem] shrink-0 rounded-lg drop-shadow-md"
hidePlaceholderOnHover
zoomOnHover
>
<div className="pointer-events-none z-10 flex h-full bg-panel-background-poster-overlay p-3 opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100">
<div
<Button
className="pointer-events-auto h-fit"
onClick={(isSeries || item.Size === 1) ? editSeriesModalCallback : editGroupModalCallback}
tooltip="Edit Series"
>
<Icon
path={mdiPencilCircleOutline}
size="2rem"
className="text-panel-icon"
/>
</div>
<Icon path={mdiPencilCircleOutline} size="2rem" />
</Button>
</div>
{showGroupIndicator && groupCount > 1 && (
<div className="absolute bottom-0 left-0 flex w-full justify-center rounded-bl-md bg-panel-background-overlay py-1.5 text-sm font-semibold opacity-100 transition-opacity group-hover:opacity-0">
Expand All @@ -177,7 +189,15 @@ const ListViewItem = ({ groupExtras, isSeries, isSidebarOpen, item }: Props) =>
</BackgroundImagePlaceholderDiv>
</Link>
<div className="flex flex-col gap-y-3">
<div className="font-semibold" title={item.Name}>{item.Name}</div>
<div className="font-semibold">
<Link
to={viewRouteLink()}
className="transition-colors hover:text-panel-text-primary"
title={item.Name}
>
{item.Name}
</Link>
</div>

<div className="flex flex-col gap-y-3">
<div className="flex flex-nowrap items-center gap-x-3">
Expand Down
58 changes: 32 additions & 26 deletions src/components/Collection/PosterViewItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -65,14 +66,14 @@ const PosterViewItem = ({ isSeries = false, item }: Props) => {
});

return (
<Link to={viewRouteLink()}>
<div
className="group flex shrink-0 flex-col content-center gap-y-3"
style={{ width: '12.938rem' }}
>
<div
className="flex shrink-0 flex-col content-center gap-y-3"
style={{ width: '12.938rem' }}
>
<Link to={viewRouteLink()}>
<BackgroundImagePlaceholderDiv
image={mainPoster}
className="h-[19rem] rounded-lg border border-panel-border drop-shadow-md"
className="group h-[19rem] rounded-lg border border-panel-border drop-shadow-md"
hidePlaceholderOnHover
zoomOnHover
>
Expand All @@ -84,16 +85,13 @@ const PosterViewItem = ({ isSeries = false, item }: Props) => {
</div>
)}
<div className="pointer-events-none z-10 flex h-full bg-panel-background-poster-overlay p-3 opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100">
<div
<Button
className="pointer-events-auto h-fit"
onClick={(isSeries || item.Size === 1) ? editSeriesModalCallback : editGroupModalCallback}
tooltip="Edit Series"
>
<Icon
path={mdiPencilCircleOutline}
size="2rem"
className="text-panel-icon"
/>
</div>
<Icon path={mdiPencilCircleOutline} size="2rem" />
</Button>
</div>
{showGroupIndicator && !isSeries && groupCount > 1 && (
<div className="absolute bottom-4 left-3 flex w-[90%] justify-center rounded-lg bg-panel-background-overlay py-2 text-sm font-semibold text-panel-text opacity-100 transition-opacity group-hover:opacity-0">
Expand All @@ -102,20 +100,28 @@ const PosterViewItem = ({ isSeries = false, item }: Props) => {
</div>
)}
</BackgroundImagePlaceholderDiv>
<div>
<p className="line-clamp-1 text-ellipsis text-center text-sm font-semibold" title={item.Name}>{item.Name}</p>
{showEpisodeCount && (
<p
className="line-clamp-1 text-ellipsis text-center text-sm font-semibold opacity-65"
title={episodeCount.toString()}
>
{episodeCount}
&nbsp;Episodes
</p>
)}
</div>
</Link>
<div>
<p className="line-clamp-1 text-ellipsis text-center text-sm font-semibold">
<Link
to={viewRouteLink()}
className="transition-colors hover:text-panel-text-primary"
title={item.Name}
>
{item.Name}
</Link>
</p>
{showEpisodeCount && (
<p
className="line-clamp-1 text-ellipsis text-center text-sm font-semibold opacity-65"
title={episodeCount.toString()}
>
{episodeCount}
&nbsp;Episodes
</p>
)}
</div>
</Link>
</div>
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/Collection/Series/EditSeriesModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Collection/Series/EditSeriesTabs/Action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const Action = (
) => (
<div
className={cx(
'flex flex-row justify-between gap-y-2 cursor-pointer hover:text-panel-text-primary',
'flex flex-row justify-between gap-y-2 cursor-pointer hover:text-panel-text-primary transition-colors',
scroll ? 'mr-4' : '',
)}
onClick={onClick}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const NameTab = ({ seriesId }: Props) => {
<div className="shoko-scrollbar flex grow flex-col gap-y-2 overflow-y-auto bg-panel-input pr-4">
{seriesData?.AniDB?.Titles.map(title => (
<div
className="flex justify-between last:border-none hover:text-panel-text-primary"
className="flex justify-between transition-colors last:border-none hover:text-panel-text-primary"
key={title.Name + title.Language}
onClick={() => setName(title.Name)}
>
Expand Down
7 changes: 4 additions & 3 deletions src/components/Collection/SeriesTopPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -33,16 +34,16 @@ const SeriesTag = React.memo(({ text, type }: { text: string, type: 'User' | 'An
});

return (
<div
<Button
className={cx(
'text-sm font-semibold flex gap-x-3 items-center border-2 border-panel-tags rounded-lg py-2 px-3 whitespace-nowrap capitalize h-fit cursor-pointer',
type === 'User' ? 'text-panel-icon-important' : 'text-panel-icon-action',
)}
onClick={handleClick}
>
<Icon path={mdiTagTextOutline} size="1.25rem" />
<span className="text-panel-text">{text}</span>
</div>
<span className="text-panel-text transition-colors hover:text-panel-text-primary">{text}</span>
</Button>
);
});

Expand Down
59 changes: 30 additions & 29 deletions src/components/Collection/TimelineSidebar.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -17,42 +16,44 @@ const TimelineItem = ({ series }: { series: SeriesType }) => {
: series.AniDB?.Type;

return (
<Link to={`/webui/collection/series/${series.IDs.ID}`}>
<div className="flex gap-x-3" key={series.IDs.ID}>
<div className="flex gap-x-3" key={series.IDs.ID}>
<Link to={`/webui/collection/series/${series.IDs.ID}`}>
<BackgroundImagePlaceholderDiv
image={mainPoster}
className="h-24 w-[4.4375rem] shrink-0 rounded-lg border border-panel-border drop-shadow-md"
className="group h-24 w-[4.4375rem] shrink-0 rounded-lg border border-panel-border drop-shadow-md"
overlayOnHover
zoomOnHover
/>
<div className="flex flex-col font-semibold">
<div className="flex gap-y-2">
{dayjs(series.AniDB?.AirDate).year()}
&nbsp;|&nbsp;
<div className="text-panel-text-important">{seriesType}</div>
</div>
<div className="line-clamp-2">{series.Name}</div>
</Link>
<div className="flex flex-col font-semibold">
<div className="flex gap-y-2">
{dayjs(series.AniDB?.AirDate).year()}
&nbsp;|&nbsp;
<div className="text-panel-text-important">{seriesType}</div>
</div>
<div className="line-clamp-2">
<Link
to={`/webui/collection/series/${series.IDs.ID}`}
className="transition-colors hover:text-panel-text-primary"
title={series.Name}
>
{series.Name}
</Link>
</div>
</div>
</Link>
</div>
);
};

const TimelineSidebar = ({ isFetching, series }: { isFetching: boolean, series: SeriesType[] }) => (
<div className="flex min-h-full overflow-hidden transition-all">
<div className="ml-8 flex w-[26.125rem] grow flex-col gap-y-6 rounded-lg border border-panel-border bg-panel-background p-6">
<div className="text-xl font-semibold">Timeline</div>
{isFetching
? (
<div className="flex grow items-center justify-center text-panel-text-primary">
<Icon path={mdiLoading} size={3} spin />
</div>
)
: (
<div className="flex flex-col gap-y-3">
{series.map(item => <TimelineItem series={item} key={item.IDs.ID} />)}
</div>
)}
</div>
</div>
<ShokoPanel
title="Timeline"
className="sticky top-24 ml-6 !h-[calc(100vh-18rem)] w-[26.5rem]"
contentClassName="gap-y-3"
isFetching={isFetching}
>
{series.map(item => <TimelineItem series={item} key={item.IDs.ID} />)}
</ShokoPanel>
);

export default TimelineSidebar;
4 changes: 2 additions & 2 deletions src/components/Dashboard/DashboardSettingsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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')}
Expand All @@ -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')}
Expand Down
Loading

0 comments on commit 0d64c98

Please sign in to comment.