Show channel counts in the left CategoryNav sidebar (Feed/Channels/Saved)

Same "channels per category" counts as the categories management page,
now next to each button in the sidebar used across all three pages.
Categories already carry channel_count; "Все"/"Без категории" counts are
derived client-side from one extra unfiltered channels query, reused
across the three pages via a shared ['channels', 'all-for-counts'] key.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
vrubelroman 2026-09-16 20:38:06 +00:00
parent cdb1c2ded2
commit 44f81f0f0d
5 changed files with 62 additions and 6 deletions

View file

@ -63,6 +63,10 @@
}
.category-nav button {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
text-align: left;
padding: 6px 10px;
border: none;
@ -76,6 +80,14 @@
font-weight: 600;
}
.category-nav-count {
font-size: 11px;
color: #999;
background: #eee;
border-radius: 8px;
padding: 1px 6px;
}
.content {
flex: 1;
min-width: 0;

View file

@ -6,16 +6,20 @@ interface Props {
categories: CategoryDto[]
value: CategoryFilter
onChange: (filter: CategoryFilter) => void
allCount?: number
uncategorizedCount?: number
}
function CategoryNav({ categories, value, onChange }: Props) {
function CategoryNav({ categories, value, onChange, allCount, uncategorizedCount }: Props) {
return (
<nav className="category-nav">
<button className={value === 'all' ? 'active' : ''} onClick={() => onChange('all')}>
Все
{allCount != null && <span className="category-nav-count">{allCount}</span>}
</button>
<button className={value === 'uncategorized' ? 'active' : ''} onClick={() => onChange('uncategorized')}>
Без категории
{uncategorizedCount != null && <span className="category-nav-count">{uncategorizedCount}</span>}
</button>
{categories.map((category) => (
<button
@ -24,6 +28,7 @@ function CategoryNav({ categories, value, onChange }: Props) {
onClick={() => onChange(category.id)}
>
{category.name}
<span className="category-nav-count">{category.channel_count}</span>
</button>
))}
</nav>

View file

@ -12,6 +12,13 @@ function Channels() {
const categoriesQuery = useQuery({ queryKey: ['categories'], queryFn: listCategories })
const allChannelsQuery = useQuery({
queryKey: ['channels', 'all-for-counts'],
queryFn: () => listChannels({ subscribed: true }),
})
const allChannels = allChannelsQuery.data ?? []
const uncategorizedCount = allChannels.filter((c) => c.category_ids.length === 0).length
const channelsQuery = useQuery({
queryKey: ['channels', filter],
queryFn: () =>
@ -74,7 +81,13 @@ function Channels() {
)}
<div className="layout">
<CategoryNav categories={categories} value={filter} onChange={setFilter} />
<CategoryNav
categories={categories}
value={filter}
onChange={setFilter}
allCount={allChannels.length}
uncategorizedCount={uncategorizedCount}
/>
<div className="content">
<input

View file

@ -1,6 +1,6 @@
import { useMutation, useInfiniteQuery, useQuery, useQueryClient } from '@tanstack/react-query'
import { Link } from 'react-router-dom'
import { getFeed, getSyncStatus, listCategories, logout, syncVideos } from '../api/client'
import { getFeed, getSyncStatus, listCategories, listChannels, logout, syncVideos } from '../api/client'
import CategoryNav, { type CategoryFilter } from '../components/CategoryNav'
import VideoCard from '../components/VideoCard'
import { useState } from 'react'
@ -12,6 +12,13 @@ function Feed() {
const categoriesQuery = useQuery({ queryKey: ['categories'], queryFn: listCategories })
const categories = categoriesQuery.data ?? []
const allChannelsQuery = useQuery({
queryKey: ['channels', 'all-for-counts'],
queryFn: () => listChannels({ subscribed: true }),
})
const allChannels = allChannelsQuery.data ?? []
const uncategorizedCount = allChannels.filter((c) => c.category_ids.length === 0).length
const feedQuery = useInfiniteQuery({
queryKey: ['feed', filter],
queryFn: ({ pageParam }) =>
@ -69,7 +76,13 @@ function Feed() {
)}
<div className="layout">
<CategoryNav categories={categories} value={filter} onChange={setFilter} />
<CategoryNav
categories={categories}
value={filter}
onChange={setFilter}
allCount={allChannels.length}
uncategorizedCount={uncategorizedCount}
/>
<div className="content">
{feedQuery.isLoading && <p>Загрузка...</p>}

View file

@ -1,6 +1,6 @@
import { useInfiniteQuery, useQuery } from '@tanstack/react-query'
import { Link } from 'react-router-dom'
import { getFeed, listCategories } from '../api/client'
import { getFeed, listCategories, listChannels } from '../api/client'
import CategoryNav, { type CategoryFilter } from '../components/CategoryNav'
import VideoCard from '../components/VideoCard'
import { useState } from 'react'
@ -11,6 +11,13 @@ function Saved() {
const categoriesQuery = useQuery({ queryKey: ['categories'], queryFn: listCategories })
const categories = categoriesQuery.data ?? []
const allChannelsQuery = useQuery({
queryKey: ['channels', 'all-for-counts'],
queryFn: () => listChannels({ subscribed: true }),
})
const allChannels = allChannelsQuery.data ?? []
const uncategorizedCount = allChannels.filter((c) => c.category_ids.length === 0).length
const feedQuery = useInfiniteQuery({
queryKey: ['feed', 'saved', filter],
queryFn: ({ pageParam }) =>
@ -38,7 +45,13 @@ function Saved() {
</header>
<div className="layout">
<CategoryNav categories={categories} value={filter} onChange={setFilter} />
<CategoryNav
categories={categories}
value={filter}
onChange={setFilter}
allCount={allChannels.length}
uncategorizedCount={uncategorizedCount}
/>
<div className="content">
{feedQuery.isLoading && <p>Загрузка...</p>}