Remove watch/download buttons from feed video cards

Cards stay fully clickable via thumbnail and title; downloads are
managed from the video page. On the Saved page the download button
remains (status/delete), and the dead .button-link styles are removed.
This commit is contained in:
vrubelroman 2026-09-22 07:53:19 +00:00
parent d4950f6979
commit fb6e639309
4 changed files with 71 additions and 14 deletions

View file

@ -55,12 +55,12 @@ h2 { color: var(--text); font-size: 18px; line-height: 1.3; font-weight: 650; }
.page-subtitle { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.5; }
.page-subtitle a { color: var(--accent); text-decoration: none; font-weight: 650; }
.page-subtitle a:hover { text-decoration: underline; }
button, .button-primary, .button-secondary, .button-quiet, .button-danger, .button-link { transition: background .16s, color .16s, border-color .16s; }
.button-primary, .button-secondary, .button-danger, .button-link { min-height: 42px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; border-radius: 8px; padding: 0 15px; text-decoration: none; font-size: 13px; font-weight: 650; white-space: nowrap; }
button, .button-primary, .button-secondary, .button-quiet, .button-danger { transition: background .16s, color .16s, border-color .16s; }
.button-primary, .button-secondary, .button-danger { min-height: 42px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; border-radius: 8px; padding: 0 15px; text-decoration: none; font-size: 13px; font-weight: 650; white-space: nowrap; }
.button-primary { border: 1px solid var(--accent); background: var(--accent); color: #081521; }
.button-primary:hover { background: #79c1ff; border-color: #79c1ff; }
.button-secondary, .button-link { border: 1px solid var(--border); background: var(--surface-raised); color: var(--text); }
.button-secondary:hover, .button-link:hover { background: var(--hover); border-color: #555; }
.button-secondary { border: 1px solid var(--border); background: var(--surface-raised); color: var(--text); }
.button-secondary:hover { background: var(--hover); border-color: #555; }
.button-quiet { min-height: 40px; padding: 0 10px; display: inline-flex; align-items: center; gap: 7px; background: transparent; border: 0; color: var(--muted); border-radius: 8px; font-size: 13px; text-decoration: none; }
.button-quiet:hover { color: var(--text); background: var(--hover); }
.button-danger { background: #a72c2a; border: 1px solid #a72c2a; color: white; }
@ -88,7 +88,7 @@ button, .button-primary, .button-secondary, .button-quiet, .button-danger, .butt
.video-channel { color: #c8c8c8; }
.video-meta span + span::before { content: '·'; margin-right: 7px; color: var(--subtle); }
.video-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 13px; }
.video-actions .button-link, .video-actions .button-secondary { min-height: 36px; padding: 0 11px; }
.video-actions .button-secondary { min-height: 36px; padding: 0 11px; }
.download-inline-actions, .download-error { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.download-badge { position: relative; display: inline-flex; align-items: center; gap: 5px; min-height: 36px; overflow: hidden; border-radius: 7px; padding: 0 10px; background: var(--surface-raised); color: var(--muted); font-size: 12px; white-space: nowrap; }
.download-badge.completed { color: var(--success); background: var(--success-soft); }
@ -277,7 +277,7 @@ button, .button-primary, .button-secondary, .button-quiet, .button-danger, .butt
.video-thumbnail { border-radius: 9px; }
.video-info { padding: 10px 2px 0; }
.video-actions { padding-top: 11px; }
.video-actions .button-link, .video-actions .button-secondary, .download-badge { min-height: 44px; }
.video-actions .button-secondary, .download-badge { min-height: 44px; }
.channels-toolbar { align-items: stretch; }
.manage-link { width: 43px; flex: none; overflow: hidden; font-size: 0; padding: 0; }
.manage-link svg { flex: none; }
@ -304,7 +304,7 @@ button, .button-primary, .button-secondary, .button-quiet, .button-danger, .butt
}
@media (min-width: 621px) and (max-width: 699px) { .video-grid { grid-template-columns: 1fr; } }
@media (pointer: coarse) {
.video-actions .button-link, .video-actions .button-secondary, .download-badge, .category-nav button, .local-filter-nav a, .mobile-category-nav a, .chip, .chip-edit, .category-checkbox, .unsubscribe-button, .sidebar-badge { min-height: 44px; }
.video-actions .button-secondary, .download-badge, .category-nav button, .local-filter-nav a, .mobile-category-nav a, .chip, .chip-edit, .category-checkbox, .unsubscribe-button, .sidebar-badge { min-height: 44px; }
.sidebar-badge { display: inline-flex; align-items: center; }
.view-toggle a { min-height: 44px; }
.reorder-buttons .icon-button { width: 40px; height: 40px; }

View file

@ -2,13 +2,13 @@ import { Link, useLocation } from 'react-router-dom'
import type { FeedVideoDto } from '../api/client'
import { formatDuration, formatRelativeTime } from '../utils/format'
import DownloadButton from './DownloadButton'
import Icon from './Icon'
interface Props {
video: FeedVideoDto
showActions?: boolean
}
function VideoCard({ video }: Props) {
function VideoCard({ video, showActions = false }: Props) {
const duration = formatDuration(video.duration_seconds)
const href = `/video/${video.youtube_video_id}`
const location = useLocation()
@ -30,10 +30,7 @@ function VideoCard({ video }: Props) {
{video.title}
</Link>
<div className="video-meta"><span className="video-channel">{video.channel.title}</span><span>{formatRelativeTime(video.published_at)}</span></div>
<div className="video-actions">
<Link to={href} state={{ from }} onClick={rememberScroll} className="button-link"><Icon name="play" size={16} /> Смотреть</Link>
<DownloadButton video={video} />
</div>
{showActions && <div className="video-actions"><DownloadButton video={video} /></div>}
</div>
</li>
)

View file

@ -110,7 +110,7 @@ function Feed() {
{hasInvalidCategory || (categoryId && categoriesQuery.data && !category) ? <div className="empty-state"><h2>Категория не найдена</h2><Link className="button-primary" to="/">Ко всем видео</Link></div> : isChannelsView ? <ChannelActivityList categoryId={categoryNumber} uncategorized={isUncategorized} syncRunning={syncRunning} /> : <>
{feedQuery.isLoading && <ul className="video-grid">{Array.from({ length: 8 }, (_, index) => <VideoSkeleton key={index} />)}</ul>}
{feedQuery.isError && <div className="empty-state" role="alert"><Icon name="alert" size={28} /><h2>Не удалось загрузить видео</h2><p>Проверь соединение и попробуй ещё раз.</p><button className="button-primary" onClick={() => feedQuery.refetch()}>Повторить</button></div>}
{!feedQuery.isLoading && !feedQuery.isError && items.length > 0 && <ul className="video-grid">{items.map((video) => <VideoCard key={video.youtube_video_id} video={video} />)}</ul>}
{!feedQuery.isLoading && !feedQuery.isError && items.length > 0 && <ul className="video-grid">{items.map((video) => <VideoCard key={video.youtube_video_id} video={video} showActions={isLocal} />)}</ul>}
{!feedQuery.isLoading && !feedQuery.isError && items.length === 0 && <div className="empty-state"><span className="empty-icon"><Icon name={syncRunning ? 'refresh' : isLocal ? 'server' : search ? 'search' : 'folder'} size={28} /></span><h2>{syncRunning ? 'Загружаем новые видео' : search ? 'Ничего не найдено' : isLocal ? 'Пока нет сохранённых видео' : isUncategorized ? 'Все каналы распределены' : 'Здесь пока нет видео'}</h2><p>{syncRunning ? 'Подписки и лента обновляются. Видео появятся здесь автоматически.' : search ? 'Попробуй другой запрос.' : isLocal ? 'Нажми «Скачать» у понравившегося ролика, и он появится здесь.' : 'Добавь каналы в категорию или обнови ленту.'}</p>{!search && !isLocal && !syncRunning && <Link className="button-primary" to="/channels">Перейти к каналам</Link>}</div>}
{feedQuery.hasNextPage && <button className="button-secondary load-more" onClick={() => feedQuery.fetchNextPage()} disabled={feedQuery.isFetchingNextPage}>{feedQuery.isFetchingNextPage ? 'Загрузка…' : 'Показать ещё'}</button>}
</>}