diff --git a/client/src/javascript/components/sidebar/SidebarFilter.tsx b/client/src/javascript/components/sidebar/SidebarFilter.tsx index fecbe1d0..1a259bbc 100644 --- a/client/src/javascript/components/sidebar/SidebarFilter.tsx +++ b/client/src/javascript/components/sidebar/SidebarFilter.tsx @@ -3,6 +3,7 @@ import {FC, ReactNode} from 'react'; import {useLingui} from '@lingui/react'; import Badge from '../general/Badge'; +import Size from '../general/Size'; interface SidebarFilterProps { name: string; @@ -10,18 +11,26 @@ interface SidebarFilterProps { isActive: boolean; slug: string; count: number; + size?: number; handleClick: (slug: string) => void; } -const SidebarFilter: FC = (props: SidebarFilterProps) => { - const {isActive, count, slug, icon, handleClick} = props; +const SidebarFilter: FC = ({ + name: _name, + icon, + isActive, + slug, + count, + size, + handleClick, +}: SidebarFilterProps) => { const {i18n} = useLingui(); const classNames = classnames('sidebar-filter__item', { 'is-active': isActive, }); - let {name} = props; + let name = _name; if (name === '') { name = i18n._('filter.all'); } else if (name === 'untagged') { @@ -51,8 +60,9 @@ const SidebarFilter: FC = (props: SidebarFilterProps) => { onClick={() => handleClick(slug)} role="menuitem"> {icon} - {name} + {name} {count} + {size && } ); @@ -60,6 +70,7 @@ const SidebarFilter: FC = (props: SidebarFilterProps) => { SidebarFilter.defaultProps = { icon: undefined, + size: undefined, }; export default SidebarFilter; diff --git a/client/src/javascript/components/sidebar/TagFilters.tsx b/client/src/javascript/components/sidebar/TagFilters.tsx index 1b792108..3be5069a 100644 --- a/client/src/javascript/components/sidebar/TagFilters.tsx +++ b/client/src/javascript/components/sidebar/TagFilters.tsx @@ -35,6 +35,7 @@ const TagFilters: FC = observer(() => { isActive={filter === TorrentFilterStore.filters.tagFilter} name={filter} slug={filter} + size={TorrentFilterStore.taxonomy.tagSizes[filter]} /> )); diff --git a/client/src/javascript/components/sidebar/TrackerFilters.tsx b/client/src/javascript/components/sidebar/TrackerFilters.tsx index 7a990cf4..50fe50cf 100644 --- a/client/src/javascript/components/sidebar/TrackerFilters.tsx +++ b/client/src/javascript/components/sidebar/TrackerFilters.tsx @@ -34,6 +34,7 @@ const TrackerFilters: FC = observer(() => { isActive={filter === TorrentFilterStore.filters.trackerFilter} name={filter} slug={filter} + size={TorrentFilterStore.taxonomy.trackerSizes[filter]} /> )); diff --git a/client/src/javascript/stores/TorrentFilterStore.ts b/client/src/javascript/stores/TorrentFilterStore.ts index bc971c8b..6951cbbe 100644 --- a/client/src/javascript/stores/TorrentFilterStore.ts +++ b/client/src/javascript/stores/TorrentFilterStore.ts @@ -20,7 +20,9 @@ class TorrentFilterStore { taxonomy: Taxonomy = { statusCounts: {}, tagCounts: {}, + tagSizes: {}, trackerCounts: {}, + trackerSizes: {}, }; @computed get isFilterActive() { diff --git a/client/src/sass/components/_sidebar-filter.scss b/client/src/sass/components/_sidebar-filter.scss index 5bc4b1cb..2efd9a03 100644 --- a/client/src/sass/components/_sidebar-filter.scss +++ b/client/src/sass/components/_sidebar-filter.scss @@ -15,6 +15,9 @@ padding: 3px 20px; text-align: start; transition: color 0.25s; + display: flex; + align-items: center; + width: 100%; &:focus-visible, &:hover { @@ -53,6 +56,13 @@ } } + .name { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + max-width: 100px; + } + .icon { display: inline-block; @include themes.theme('fill', 'sidebar-filter--foreground'); @@ -62,6 +72,10 @@ vertical-align: middle; width: auto; } + + .size { + margin-left: auto; + } } .badge { diff --git a/server/services/taxonomyService.ts b/server/services/taxonomyService.ts index 03ac45df..e84d7610 100644 --- a/server/services/taxonomyService.ts +++ b/server/services/taxonomyService.ts @@ -15,7 +15,9 @@ class TaxonomyService extends BaseService { taxonomy: Taxonomy = { statusCounts: {'': 0}, tagCounts: {'': 0, untagged: 0}, + tagSizes: {}, trackerCounts: {'': 0}, + trackerSizes: {}, }; lastTaxonomy: Taxonomy = this.taxonomy; @@ -61,7 +63,9 @@ class TaxonomyService extends BaseService { this.lastTaxonomy = { statusCounts: {...this.taxonomy.statusCounts}, tagCounts: {...this.taxonomy.tagCounts}, + tagSizes: {...this.taxonomy.tagSizes}, trackerCounts: {...this.taxonomy.trackerCounts}, + trackerSizes: {...this.taxonomy.trackerSizes}, }; torrentStatusMap.forEach((status) => { @@ -70,7 +74,9 @@ class TaxonomyService extends BaseService { this.taxonomy.statusCounts[''] = 0; this.taxonomy.tagCounts = {'': 0, untagged: 0}; + this.taxonomy.tagSizes = {}; this.taxonomy.trackerCounts = {'': 0}; + this.taxonomy.trackerSizes = {}; }; handleProcessTorrentListEnd = ({torrents}: {torrents: TorrentList}) => { @@ -93,7 +99,9 @@ class TaxonomyService extends BaseService { handleProcessTorrent = (torrentProperties: TorrentProperties) => { this.incrementStatusCounts(torrentProperties.status); this.incrementTagCounts(torrentProperties.tags); + this.incrementTagSizes(torrentProperties.tags, torrentProperties.sizeBytes); this.incrementTrackerCounts(torrentProperties.trackerURIs); + this.incrementTrackerSizes(torrentProperties.trackerURIs, torrentProperties.sizeBytes); }; incrementStatusCounts(statuses: Array) { @@ -116,6 +124,16 @@ class TaxonomyService extends BaseService { }); } + incrementTagSizes(tags: TorrentProperties['tags'], sizeBytes: TorrentProperties['sizeBytes']) { + tags.forEach((tag) => { + if (this.taxonomy.tagSizes[tag] != null) { + this.taxonomy.tagSizes[tag] += sizeBytes; + } else { + this.taxonomy.tagSizes[tag] = sizeBytes; + } + }); + } + incrementTrackerCounts(trackers: TorrentProperties['trackerURIs']) { trackers.forEach((tracker) => { if (this.taxonomy.trackerCounts[tracker] != null) { @@ -125,6 +143,16 @@ class TaxonomyService extends BaseService { } }); } + + incrementTrackerSizes(trackers: TorrentProperties['trackerURIs'], sizeBytes: TorrentProperties['sizeBytes']) { + trackers.forEach((tracker) => { + if (this.taxonomy.trackerSizes[tracker] != null) { + this.taxonomy.trackerSizes[tracker] += sizeBytes; + } else { + this.taxonomy.trackerSizes[tracker] = sizeBytes; + } + }); + } } export default TaxonomyService; diff --git a/shared/types/Taxonomy.ts b/shared/types/Taxonomy.ts index 8788ec3b..388699d9 100644 --- a/shared/types/Taxonomy.ts +++ b/shared/types/Taxonomy.ts @@ -1,5 +1,7 @@ export interface Taxonomy { statusCounts: Record; tagCounts: Record; + tagSizes: Record; trackerCounts: Record; + trackerSizes: Record; }