myYouTube/analytics/2026-09-18-feed-card-cleanup.md
vrubelroman fb6e639309 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.
2026-09-22 07:53:19 +00:00

60 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Чистка карточек видео: убрать «Смотреть» и «Скачать» из ленты, оставить действия на /local
## Задача
Убрать из карточек видео (`VideoCard`) кнопки «Смотреть» и «Скачать» на всех ленточных маршрутах: `/`, `/category/:id`, `/uncategorized`, `/search`, а также на странице видео канала `/channels/:id/videos`. Карточка остаётся кликабельной целиком через превью и заголовок (это ссылки), скачивание остаётся доступным со страницы видео. Исключение — `/local` («На сервере»): там кнопка скачивания остаётся, т.к. показывает статус загрузки и участвует в управлении копиями. Кнопка «Смотреть» не нужна нигде в карточках (включая /local) — превью/заголовок и так ведут на страницу видео.
## Контекст
- `VideoCard` (frontend/src/components/VideoCard.tsx) сейчас рендерит: thumbnail-Link (с `aria-label="Смотреть: …"`), title-Link, `.video-meta`, и блок `.video-actions` с двумя элементами: «Смотреть» (`Link className="button-link"` + `Icon name="play"`) и `<DownloadButton video={video} />`.
- `VideoCard` используется ровно в двух местах: `Feed.tsx` (строка 113 — все режимы ленты, включая `/local` и `/search`) и `ChannelVideos.tsx` (строка 21). Компактные карточки в режиме «Каналы» (`CompactVideoCard`) уже без кнопок и не затрагиваются.
- `DownloadButton` остаётся нужным в трёх местах: карточки `/local`, страница видео `VideoPage` (`showDelete` — там живёт «Удалить копию»), и он не меняется. На карточке `/local` сегодня он рендерится **без** `showDelete` (кнопки «Удалить копию» в карточке нет и не было — она только на `VideoPage`); на `/local` показываются статусы («Скачать» / «Скачивается N%» / «В очереди…» / «На сервере» / «Повторить» / «Загрузить снова»). Поведение на `/local` менять не требуется — сохранить как есть.
- Кнопка «Смотреть» — единственное использование класса `.button-link` и иконки `Icon` в `VideoCard`. После удаления кнопки класс `.button-link` становится мёртвым во всём CSS (проверено rg: только App.css и VideoCard.tsx), а импорт `Icon` в `VideoCard` — неиспользуемым (`noUnusedLocals` в tsconfig → ошибка сборки, если не убрать).
- В `DownloadButton` кэш-инвалидация на завершении/удалении (`['feed']`, `['video', id]`) не зависит от места рендера — на `/local` и `VideoPage` она продолжит работать как раньше.
## Затронутые подсистемы и файлы
Только frontend. Backend, тесты, миграции — не трогаем.
- `frontend/src/components/VideoCard.tsx` — добавить опциональный проп `showActions` (default `false`); блок `.video-actions` рендерить только при `showActions` и только с `<DownloadButton>`; удалить «Смотреть» и импорт `Icon`; `DownloadButton` импорт оставить; `aria-label` на thumbnail-Link сохранить.
- `frontend/src/pages/Feed.tsx` — передать `showActions={isLocal}` в `VideoCard` (строка 113). `isLocal` уже вычислен (строка 19).
- `frontend/src/pages/ChannelVideos.tsx` — без изменений (проп по умолчанию `false`).
- `frontend/src/App.css` — чистка мёртвых правил `.button-link`:
- строка 58 (transition-список) — убрать `.button-link`;
- строка 59 (общий стиль кнопок) — убрать `.button-link`;
- строки 62–63 (`.button-secondary, .button-link` + hover) — оставить только `.button-secondary`;
- строка 91 — `.video-actions .button-link, .video-actions .button-secondary` → оставить только `.video-actions .button-secondary` (secondary внутри actions остаётся: его рендерит DownloadButton на /local);
- строка 280 (media ≤620px) — убрать `.video-actions .button-link,` из списка;
- строка 307 (pointer: coarse) — убрать `.video-actions .button-link,` из списка;
- `.video-actions` (строка 90) и `.download-*` правила остаются — используются DownloadButton на `/local` и `VideoPage`.
- `README.md` — не трогаем (кнопки карточек в README не документируются; это полировка UI, не фича).
## Критерии приёмки
1. На `/`, `/category/:id`, `/uncategorized`, `/search` и `/channels/:id/videos` в карточках нет ни «Смотреть», ни «Скачать»; карточка кликабельна через превью и заголовок, `aria-label="Смотреть: …"` на thumbnail-Link сохранён.
2. На `/local` кнопка скачивания осталась и ведёт себя как раньше: статусы (Скачать/Скачивается N%/В очереди…/Обработка…/На сервере/Повторить/Загрузить снова) и инвалидация кэшей `['feed']`/`['video', id]` по завершении работают. «Смотреть» в карточках нет и на `/local`.
3. `DownloadButton` не сломан нигде: на `VideoPage` (`showDelete`) — скачивание, статусы и «Удалить копию» (с инвалидацией) работают как раньше.
4. CSS почищен: `rg "button-link" frontend/src` не находит ни одного вхождения (ни в CSS, ни в TSX); правила `.video-actions` и `.download-*` остаются живыми (используются DownloadButton).
5. `npm run lint` и `npm run build` в `frontend/` чистые (нет unused-импортов/локалов).
6. Backend не тронут: `git status` показывает изменения только в `frontend/` и `analytics/`; `pytest` не требуется (изменений backend/тестов нет), при желании прогоняется без изменений.
7. Деплой по правилу команды: `docker compose up -d --build`, `curl http://localhost:8080/api/health` → OK.
## План
1. `VideoCard.tsx`: `interface Props { video: FeedVideoDto; showActions?: boolean }`; деструктуризация `({ video, showActions = false })`; `.video-actions` рендерить условно `{showActions && <div className="video-actions"><DownloadButton video={video} /></div>}`; удалить «Смотреть»-Link и импорт `Icon`.
2. `Feed.tsx`: `<VideoCard key={…} video={video} showActions={isLocal} />`.
3. `App.css`: вычистить `.button-link` из строк 58, 59, 62, 63, 91, 280, 307 (по списку выше), не трогая `.video-actions` и `.download-*`.
4. Проверки: `rg -n "button-link" frontend/src` → пусто; `npm run lint`, `npm run build` в `frontend/`; ручная проверка: лента/категории/поиск/страница канала без кнопок, `/local` с кнопкой и статусами, `VideoPage` с «Удалить копию»; деплой и health-проверка.
## Риски и ограничения
- **Не потерять действия на /local**: условие рендера должно опираться на `isLocal` из `Feed.tsx`, а не на проп, вычисляемый внутри карточки (VideoCard не знает маршрут надёжно — точнее держать флаг в родителе). `ChannelVideos` по умолчанию без действий.
- **`Icon`/`DownloadButton` импорты**: после удаления «Смотреть» импорт `Icon` в `VideoCard` неиспользуемый — при `noUnusedLocals` сборка упадёт, если его оставить; импорт `DownloadButton` нужен (условный рендер).
- **«Удалить копию» на карточке /local**: в карточке её нет и не было (DownloadButton там рендерится без `showDelete`); критерий — «не сломать», а не «добавить». Удаление копии остаётся на `VideoPage` (проп `showDelete` не трогаем).
- **CSS-чистка**: класс `.button-link` после правки нигде не используется — удалять его правила целиком; `.video-actions .button-secondary` оставить (secondary-кнопки DownloadButton в блоке действий). Медиа-правила ≤620px и pointer:coarse править точечно, не трогая соседние селекторы.
- **Empty-state /local**: подсказка «Нажми „Скачать“ у понравившегося ролика…» остаётся корректной, т.к. на /local кнопка сохраняется. Но на обычной ленте кнопки больше нет — путь скачивания теперь только через страницу видео (это осознанное UX-решение задачи).
- **`Feed.tsx` уже загружен**: изменения ограничиваются одной строкой рендера — не усложнять компонент дополнительной логикой.
## Журнал изменений
- 2026-09-18: документ создан перед реализацией. Зафиксированы решения: проп `showActions` в `VideoCard` (default false); «Смотреть» убирается везде, DownloadButton остаётся только на `/local` (как сегодня, без `showDelete`); `ChannelVideos` не меняется; CSS: полное удаление мёртвого класса `.button-link`, сохранение `.video-actions`/`.download-*`; README не трогаем; backend не трогаем.