1019 lines
28 KiB
Markdown
1019 lines
28 KiB
Markdown
|
|
# UI/UX-спецификация: персональный YouTube-клиент
|
|||
|
|
|
|||
|
|
**Назначение:** передать coding agent вместе с основным техническим заданием.
|
|||
|
|
**Формат:** single-user self-hosted web app, в будущем PWA/mobile client.
|
|||
|
|
|
|||
|
|
## 1. Концепция
|
|||
|
|
|
|||
|
|
Приложение должно ощущаться как персональная лента YouTube-подписок, но с нормальной категоризацией каналов и локальным хранением выбранных видео.
|
|||
|
|
|
|||
|
|
Пользовательский сценарий:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Открыть приложение
|
|||
|
|
→ выбрать категорию
|
|||
|
|
→ увидеть последние видео каналов этой категории
|
|||
|
|
→ смотреть через YouTube
|
|||
|
|
→ при желании нажать "Скачать"
|
|||
|
|
→ после загрузки видеть "На сервере"
|
|||
|
|
→ дальше смотреть локальную копию через MeTube
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Интерфейс не должен выглядеть как admin panel. Это consumer media UI.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Общий layout
|
|||
|
|
|
|||
|
|
Desktop:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌──────────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ Header │
|
|||
|
|
├──────────────────────┬───────────────────────────────────────────────┤
|
|||
|
|
│ Sidebar │ Main content │
|
|||
|
|
│ │ │
|
|||
|
|
│ Все видео │ Video feed │
|
|||
|
|
│ Без категории │ │
|
|||
|
|
│ На сервере │ │
|
|||
|
|
│ │ │
|
|||
|
|
│ КАТЕГОРИИ │ │
|
|||
|
|
│ Linux │ │
|
|||
|
|
│ Шахматы │ │
|
|||
|
|
│ Научпоп │ │
|
|||
|
|
│ │ │
|
|||
|
|
│ Каналы │ │
|
|||
|
|
│ Настройки │ │
|
|||
|
|
└──────────────────────┴───────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Sidebar: 220–260 px.
|
|||
|
|
Header: фиксированный сверху.
|
|||
|
|
Main content: responsive grid.
|
|||
|
|
|
|||
|
|
Mobile: sidebar превращается в drawer/hamburger.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Визуальный стиль
|
|||
|
|
|
|||
|
|
Тёмная тема по умолчанию.
|
|||
|
|
|
|||
|
|
Рекомендуемые design tokens:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Background main #0F0F0F
|
|||
|
|
Surface #181818
|
|||
|
|
Surface hover #272727
|
|||
|
|
Border #303030
|
|||
|
|
Primary text #F1F1F1
|
|||
|
|
Secondary text #AAAAAA
|
|||
|
|
Accent #3EA6FF
|
|||
|
|
Success/local #2BA640
|
|||
|
|
Warning/downloading #F5A623
|
|||
|
|
Error #E53935
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Использовать CSS variables, а не раскидывать цвета по компонентам.
|
|||
|
|
|
|||
|
|
Типографика:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Inter / Roboto / system-ui
|
|||
|
|
Page title 24px / 600
|
|||
|
|
Section title 18px / 600
|
|||
|
|
Video title 15–16px / 500
|
|||
|
|
Metadata 12–14px
|
|||
|
|
Buttons 14px / 500
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Header
|
|||
|
|
|
|||
|
|
Пример:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌──────────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ▶ MyTube 🔍 Поиск... ✓ 12 мин ⚙ │
|
|||
|
|
└──────────────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Слева:
|
|||
|
|
- логотип;
|
|||
|
|
- рабочее название `MyTube` или configurable app name.
|
|||
|
|
|
|||
|
|
Центр:
|
|||
|
|
- поиск по локальной БД: video title + channel title.
|
|||
|
|
|
|||
|
|
Справа:
|
|||
|
|
- sync indicator;
|
|||
|
|
- settings.
|
|||
|
|
|
|||
|
|
Sync states:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
✓ Обновлено 12 мин назад
|
|||
|
|
↻ Обновление...
|
|||
|
|
⚠ Ошибка синхронизации
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
По клику на sync indicator:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Подписки: обновлены 20:11
|
|||
|
|
Видео: обновлены 20:12
|
|||
|
|
MeTube: доступен
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Sidebar
|
|||
|
|
|
|||
|
|
Пример:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
● Все видео
|
|||
|
|
Без категории
|
|||
|
|
На сервере
|
|||
|
|
|
|||
|
|
КАТЕГОРИИ
|
|||
|
|
|
|||
|
|
🐧 Linux
|
|||
|
|
♟ Шахматы
|
|||
|
|
🔬 Научпоп
|
|||
|
|
🎮 Игры
|
|||
|
|
|
|||
|
|
+ Новая категория
|
|||
|
|
|
|||
|
|
────────────
|
|||
|
|
|
|||
|
|
Каналы
|
|||
|
|
Настройки
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Активная категория должна иметь заметный, но спокойный selected state.
|
|||
|
|
|
|||
|
|
`Все видео`, `Без категории`, `На сервере` — виртуальные категории.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Feed
|
|||
|
|
|
|||
|
|
Route:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
или:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/feed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Header выбранной категории:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Linux
|
|||
|
|
24 канала
|
|||
|
|
Обновлено 12 минут назад [↻ Обновить]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Опциональные chips:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[Все] [На сервере] [Не скачаны]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Сортировка видео:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
published_at DESC
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Video grid
|
|||
|
|
|
|||
|
|
Responsive:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
>= 1800 px → 5 columns
|
|||
|
|
>= 1400 px → 4 columns
|
|||
|
|
>= 1000 px → 3 columns
|
|||
|
|
>= 700 px → 2 columns
|
|||
|
|
mobile → 1 column
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Рекомендуемый CSS:
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. Video card
|
|||
|
|
|
|||
|
|
Пример:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌────────────────────────────────────┐
|
|||
|
|
│ │
|
|||
|
|
│ THUMBNAIL │
|
|||
|
|
│ 18:42 │
|
|||
|
|
│ │
|
|||
|
|
├────────────────────────────────────┤
|
|||
|
|
│ Linux Kernel 7.0 — What's New │
|
|||
|
|
│ The Linux Experiment │
|
|||
|
|
│ 2 часа назад │
|
|||
|
|
│ │
|
|||
|
|
│ [▶ Смотреть] [⬇ Скачать] │
|
|||
|
|
└────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Thumbnail:
|
|||
|
|
- aspect ratio 16:9;
|
|||
|
|
- duration badge справа снизу.
|
|||
|
|
|
|||
|
|
Карточка содержит:
|
|||
|
|
- thumbnail;
|
|||
|
|
- title;
|
|||
|
|
- channel name;
|
|||
|
|
- publish time;
|
|||
|
|
- duration;
|
|||
|
|
- download/local state;
|
|||
|
|
- Watch;
|
|||
|
|
- Download.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. Состояния скачивания
|
|||
|
|
|
|||
|
|
### Не скачано
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[▶ Смотреть] [⬇ Скачать]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### В очереди
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[▶ Смотреть] [В очереди...]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Скачивается
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[▶ Смотреть] [64%]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Дополнительно progress-line внизу thumbnail.
|
|||
|
|
|
|||
|
|
### Post-processing
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[▶ Смотреть] [Обработка...]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### На сервере
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[▶ Смотреть] [✓ На сервере]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Ошибка
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[▶ Смотреть] [⚠ Повторить]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Не показывать traceback.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. Video page
|
|||
|
|
|
|||
|
|
Route:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/video/:youtubeVideoId
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Desktop:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ │
|
|||
|
|
│ VIDEO PLAYER │
|
|||
|
|
│ │
|
|||
|
|
└──────────────────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
Linux Kernel 7.0 — What's New
|
|||
|
|
|
|||
|
|
The Linux Experiment
|
|||
|
|
2 часа назад [⬇ Скачать]
|
|||
|
|
|
|||
|
|
Источник: YouTube
|
|||
|
|
|
|||
|
|
[Linux] [IT]
|
|||
|
|
|
|||
|
|
────────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
Описание видео...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Если local copy существует:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Источник: ● Локальная копия · mediaVM
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
и вместо YouTube iframe используется HTML5 `<video>`.
|
|||
|
|
|
|||
|
|
Пользователь не выбирает источник вручную по умолчанию.
|
|||
|
|
|
|||
|
|
Логика:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
local available?
|
|||
|
|
yes → local player
|
|||
|
|
no → YouTube player
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Если local player вернул ошибку/404:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Локальная копия недоступна.
|
|||
|
|
Переключено на YouTube.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. Channels page
|
|||
|
|
|
|||
|
|
Route:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/channels
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Главная задача — быстро распределять подписки по категориям.
|
|||
|
|
|
|||
|
|
Пример:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Каналы
|
|||
|
|
|
|||
|
|
[Поиск каналов...] [Только без категории]
|
|||
|
|
|
|||
|
|
┌────────────────────────────────────────────────────┐
|
|||
|
|
│ ○ The Linux Experiment │
|
|||
|
|
│ [Linux ×] [IT ×] [+ Категория] │
|
|||
|
|
└────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
┌────────────────────────────────────────────────────┐
|
|||
|
|
│ ○ GothamChess │
|
|||
|
|
│ [Шахматы ×] [+ Категория] │
|
|||
|
|
└────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
┌────────────────────────────────────────────────────┐
|
|||
|
|
│ ○ Veritasium │
|
|||
|
|
│ [Научпоп ×] [+ Категория] │
|
|||
|
|
└────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Не делать отдельную страницу редактирования для каждого канала.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. Category picker
|
|||
|
|
|
|||
|
|
По кнопке:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
+ Категория
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
показывать popover:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Категории
|
|||
|
|
|
|||
|
|
☑ Linux
|
|||
|
|
☑ IT
|
|||
|
|
☐ Научпоп
|
|||
|
|
☐ Игры
|
|||
|
|
|
|||
|
|
──────────────
|
|||
|
|
+ Создать новую
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Checkbox сохраняется сразу.
|
|||
|
|
|
|||
|
|
Отдельная кнопка `Сохранить` не нужна.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. Массовая категоризация
|
|||
|
|
|
|||
|
|
Желательная функция.
|
|||
|
|
|
|||
|
|
Пользователь отмечает несколько каналов:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
☑ Channel A
|
|||
|
|
☑ Channel B
|
|||
|
|
☑ Channel C
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Появляется action bar:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Выбрано: 3
|
|||
|
|
|
|||
|
|
[Добавить в категорию] [Убрать из категории] [Отмена]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Если MVP затягивается, допускается реализовать после базовой версии.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 14. Category management
|
|||
|
|
|
|||
|
|
Route:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/settings/categories
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Пример:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Категории
|
|||
|
|
|
|||
|
|
≡ Linux 24 канала ✎ ⋮
|
|||
|
|
≡ Шахматы 12 каналов ✎ ⋮
|
|||
|
|
≡ Научпоп 8 каналов ✎ ⋮
|
|||
|
|
|
|||
|
|
[+ Новая категория]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Поддержать:
|
|||
|
|
- create;
|
|||
|
|
- rename;
|
|||
|
|
- delete;
|
|||
|
|
- reorder.
|
|||
|
|
|
|||
|
|
При удалении:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Удалить категорию "Linux"?
|
|||
|
|
|
|||
|
|
Каналы удалены не будут.
|
|||
|
|
Они просто перестанут относиться к этой категории.
|
|||
|
|
|
|||
|
|
[Отмена] [Удалить]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 15. Virtual category "Без категории"
|
|||
|
|
|
|||
|
|
Показывает каналы/видео каналов, которые ещё не распределены.
|
|||
|
|
|
|||
|
|
Header:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Без категории
|
|||
|
|
|
|||
|
|
17 каналов пока не распределены.
|
|||
|
|
|
|||
|
|
[Перейти к каналам]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 16. Virtual category "На сервере"
|
|||
|
|
|
|||
|
|
Показывает видео:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
download_status = completed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Это простая локальная библиотека без отдельного сложного media-manager.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 17. Empty states
|
|||
|
|
|
|||
|
|
### Нет категорий
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Категорий пока нет
|
|||
|
|
|
|||
|
|
Раздели подписки по темам:
|
|||
|
|
Linux, Шахматы, Научпоп и т.д.
|
|||
|
|
|
|||
|
|
[Создать первую категорию]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### В категории нет видео
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Здесь пока нет видео
|
|||
|
|
|
|||
|
|
Добавь каналы в эту категорию
|
|||
|
|
или обнови подписки.
|
|||
|
|
|
|||
|
|
[Добавить каналы]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### YouTube ещё не подключён
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Подключи свой YouTube
|
|||
|
|
|
|||
|
|
Мы импортируем список подписок и последние видео.
|
|||
|
|
Доступ к YouTube только read-only.
|
|||
|
|
|
|||
|
|
[Подключить YouTube]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 18. Loading states
|
|||
|
|
|
|||
|
|
Не использовать fullscreen spinner.
|
|||
|
|
|
|||
|
|
Использовать skeleton video cards.
|
|||
|
|
|
|||
|
|
Background sync не должен блокировать интерфейс.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 19. Error UX
|
|||
|
|
|
|||
|
|
Global toast:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Не удалось связаться с MeTube
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
или:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
YouTube временно недоступен
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Critical banner:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
⚠ Требуется повторная авторизация YouTube
|
|||
|
|
|
|||
|
|
[Подключить заново]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Background sync не должен постоянно спамить toast notifications.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 20. Settings
|
|||
|
|
|
|||
|
|
Route:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/settings
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Sections:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
YouTube
|
|||
|
|
MeTube
|
|||
|
|
Синхронизация
|
|||
|
|
Интерфейс
|
|||
|
|
О приложении
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### YouTube
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Google account:
|
|||
|
|
user@example.com
|
|||
|
|
|
|||
|
|
Статус: Подключено
|
|||
|
|
|
|||
|
|
Последняя синхронизация:
|
|||
|
|
Сегодня, 20:15
|
|||
|
|
|
|||
|
|
[Обновить сейчас]
|
|||
|
|
[Переподключить]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### MeTube
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
MeTube
|
|||
|
|
|
|||
|
|
Статус: ● Доступен
|
|||
|
|
Сервер: mediaVM
|
|||
|
|
Адрес: 192.168.8.177:8081
|
|||
|
|
|
|||
|
|
[Проверить соединение]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Не показывать на основном UI filesystem path или internal job IDs.
|
|||
|
|
|
|||
|
|
### Sync
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Подписки: каждые 6 часов
|
|||
|
|
Видео: каждые 60 минут
|
|||
|
|
|
|||
|
|
Последний запуск:
|
|||
|
|
20:12
|
|||
|
|
|
|||
|
|
[Синхронизировать сейчас]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 21. First-run onboarding
|
|||
|
|
|
|||
|
|
Flow:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Open app
|
|||
|
|
→ Подключить YouTube
|
|||
|
|
→ Google OAuth
|
|||
|
|
→ initial sync
|
|||
|
|
→ channels imported
|
|||
|
|
→ предложить категоризацию
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
После initial sync:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Готово!
|
|||
|
|
|
|||
|
|
Импортировано:
|
|||
|
|
143 канала
|
|||
|
|
|
|||
|
|
Теперь можно распределить их по категориям.
|
|||
|
|
|
|||
|
|
[Настроить категории]
|
|||
|
|
[Сделать позже]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 22. Mobile UX
|
|||
|
|
|
|||
|
|
Header:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
☰ MyTube ↻
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Категории можно показывать horizontal chips:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[Все] [Linux] [Шахматы] [Научпоп] →
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Video card:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌───────────────────────────────┐
|
|||
|
|
│ │
|
|||
|
|
│ Thumbnail │
|
|||
|
|
│ │
|
|||
|
|
└───────────────────────────────┘
|
|||
|
|
|
|||
|
|
Video title
|
|||
|
|
Channel · 2 часа назад
|
|||
|
|
|
|||
|
|
[▶ Смотреть] [⬇ Скачать]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Touch targets минимум ~44×44 px.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 23. Navigation routes
|
|||
|
|
|
|||
|
|
Рекомендуемые routes:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/ all feed
|
|||
|
|
/category/:categoryId category feed
|
|||
|
|
/channels channels
|
|||
|
|
/video/:youtubeVideoId video detail/player
|
|||
|
|
/local local videos
|
|||
|
|
/uncategorized uncategorized
|
|||
|
|
/settings settings
|
|||
|
|
/settings/categories category management
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Browser Back после просмотра видео должен возвращать:
|
|||
|
|
- в ту же категорию;
|
|||
|
|
- примерно на ту же scroll position.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 24. Components
|
|||
|
|
|
|||
|
|
Frontend должен быть разделён на reusable components:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
AppShell
|
|||
|
|
Header
|
|||
|
|
Sidebar
|
|||
|
|
CategoryNav
|
|||
|
|
VideoGrid
|
|||
|
|
VideoCard
|
|||
|
|
VideoThumbnail
|
|||
|
|
DownloadButton
|
|||
|
|
DownloadStatus
|
|||
|
|
Player
|
|||
|
|
YouTubePlayer
|
|||
|
|
LocalPlayer
|
|||
|
|
ChannelRow
|
|||
|
|
CategoryPicker
|
|||
|
|
CategoryChip
|
|||
|
|
SyncIndicator
|
|||
|
|
EmptyState
|
|||
|
|
ErrorBanner
|
|||
|
|
Toast
|
|||
|
|
ConfirmDialog
|
|||
|
|
SkeletonVideoCard
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Не делать весь UI одним React component.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 25. Feed API object
|
|||
|
|
|
|||
|
|
Желательно, чтобы backend сразу отдавал frontend всё необходимое для одной карточки:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"youtube_video_id": "abc123",
|
|||
|
|
"title": "Linux Kernel 7.0",
|
|||
|
|
"channel": {
|
|||
|
|
"id": 12,
|
|||
|
|
"youtube_channel_id": "UC...",
|
|||
|
|
"title": "The Linux Experiment",
|
|||
|
|
"thumbnail_url": "..."
|
|||
|
|
},
|
|||
|
|
"thumbnail_url": "...",
|
|||
|
|
"published_at": "2026-09-16T18:00:00Z",
|
|||
|
|
"duration_seconds": 1042,
|
|||
|
|
"categories": [
|
|||
|
|
{
|
|||
|
|
"id": 2,
|
|||
|
|
"name": "Linux"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"local": {
|
|||
|
|
"available": true,
|
|||
|
|
"status": "completed",
|
|||
|
|
"progress_percent": 100,
|
|||
|
|
"media_url": "http://..."
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Запрещён frontend pattern:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
GET feed
|
|||
|
|
→ отдельный request channel для каждой карточки
|
|||
|
|
→ отдельный request download status для каждой карточки
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Не должно быть N+1 API requests.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 26. Desktop wireframe
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌────────────────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ▶ MyTube 🔍 Поиск ✓ 12 мин ⚙ │
|
|||
|
|
├──────────────────────┬─────────────────────────────────────────────────────┤
|
|||
|
|
│ │ │
|
|||
|
|
│ ● Все видео │ Linux │
|
|||
|
|
│ Без категории │ 24 канала [↻ Обновить] │
|
|||
|
|
│ На сервере │ │
|
|||
|
|
│ │ [Все] [На сервере] [Не скачаны] │
|
|||
|
|
│ КАТЕГОРИИ │ │
|
|||
|
|
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|||
|
|
│ 🐧 Linux │ │ thumbnail │ │ thumbnail │ │ thumbnail │ │
|
|||
|
|
│ ♟ Шахматы │ │ 18:42│ │ 12:03│ │ 8:41│ │
|
|||
|
|
│ 🔬 Научпоп │ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|||
|
|
│ 🎮 Игры │ Kernel 7.0... NixOS update... New GNOME... │
|
|||
|
|
│ │ Linux Exp. Brodie R. DistroTube │
|
|||
|
|
│ + Категория │ 2 часа назад 4 часа назад вчера │
|
|||
|
|
│ │ [▶] [⬇] [▶] [64%] [▶] [✓ Local] │
|
|||
|
|
│ ───────────── │ │
|
|||
|
|
│ Каналы │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|||
|
|
│ Настройки │ │ │ │ │ │ │ │
|
|||
|
|
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|||
|
|
└──────────────────────┴─────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 27. Channels wireframe
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌──────────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ Каналы │
|
|||
|
|
│ │
|
|||
|
|
│ 🔍 Поиск каналов... [Только без категории] │
|
|||
|
|
│ │
|
|||
|
|
├──────────────────────────────────────────────────────────────────────┤
|
|||
|
|
│ ○ The Linux Experiment │
|
|||
|
|
│ [Linux ×] [IT ×] [+ Категория] │
|
|||
|
|
├──────────────────────────────────────────────────────────────────────┤
|
|||
|
|
│ ○ GothamChess │
|
|||
|
|
│ [Шахматы ×] [+ Категория] │
|
|||
|
|
├──────────────────────────────────────────────────────────────────────┤
|
|||
|
|
│ ○ Veritasium │
|
|||
|
|
│ [Научпоп ×] [+ Категория] │
|
|||
|
|
├──────────────────────────────────────────────────────────────────────┤
|
|||
|
|
│ ○ Some Channel │
|
|||
|
|
│ [+ Категория] │
|
|||
|
|
└──────────────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 28. Video page wireframe
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌──────────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ │
|
|||
|
|
│ VIDEO PLAYER │
|
|||
|
|
│ │
|
|||
|
|
└──────────────────────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
Linux Kernel 7.0 — What's New
|
|||
|
|
|
|||
|
|
The Linux Experiment
|
|||
|
|
2 часа назад
|
|||
|
|
|
|||
|
|
● Локальная копия · mediaVM [✓ На сервере]
|
|||
|
|
|
|||
|
|
[Linux] [IT]
|
|||
|
|
|
|||
|
|
────────────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
Описание видео...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Когда local отсутствует:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Источник: YouTube [⬇ Скачать]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 29. UX-антипаттерны
|
|||
|
|
|
|||
|
|
Не делать:
|
|||
|
|
- Bootstrap-like admin tables как основной UI;
|
|||
|
|
- raw JSON;
|
|||
|
|
- container names/job IDs на главном экране;
|
|||
|
|
- filesystem paths;
|
|||
|
|
- огромные формы;
|
|||
|
|
- отдельный Save после каждого checkbox;
|
|||
|
|
- модальное окно на каждое простое действие;
|
|||
|
|
- fullscreen spinner при background sync;
|
|||
|
|
- N+1 API requests;
|
|||
|
|
- слишком много badges на thumbnail;
|
|||
|
|
- сильные hover zoom animations.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 30. Accessibility
|
|||
|
|
|
|||
|
|
Минимум:
|
|||
|
|
- semantic HTML;
|
|||
|
|
- keyboard navigation;
|
|||
|
|
- visible focus ring;
|
|||
|
|
- aria-label для icon buttons;
|
|||
|
|
- alt у изображений;
|
|||
|
|
- нормальный contrast;
|
|||
|
|
- `<button>` для кнопок;
|
|||
|
|
- состояние не должно кодироваться только цветом.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 31. Icons
|
|||
|
|
|
|||
|
|
Использовать один icon set, например Lucide React.
|
|||
|
|
|
|||
|
|
Основные icons:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Home
|
|||
|
|
Folder
|
|||
|
|
Download
|
|||
|
|
Play
|
|||
|
|
Check
|
|||
|
|
RefreshCw
|
|||
|
|
Settings
|
|||
|
|
Search
|
|||
|
|
MoreVertical
|
|||
|
|
AlertTriangle
|
|||
|
|
Server
|
|||
|
|
Youtube
|
|||
|
|
Menu
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 32. Анимации
|
|||
|
|
|
|||
|
|
Минимально:
|
|||
|
|
- hover 150–200 ms;
|
|||
|
|
- popover fade;
|
|||
|
|
- drawer slide;
|
|||
|
|
- progress;
|
|||
|
|
- skeleton pulse.
|
|||
|
|
|
|||
|
|
Не делать сложные page transitions.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 33. Рекомендуемый порядок реализации UI
|
|||
|
|
|
|||
|
|
Сначала сделать интерфейс на mock data:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
App shell
|
|||
|
|
Sidebar
|
|||
|
|
Video grid
|
|||
|
|
Video card
|
|||
|
|
Channels page
|
|||
|
|
Category picker
|
|||
|
|
Video page
|
|||
|
|
Mobile responsive
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Только после визуальной проверки подключать реальные backend API.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 34. Definition of Done UI
|
|||
|
|
|
|||
|
|
UI MVP готов, если:
|
|||
|
|
|
|||
|
|
1. Пользователь может подключить YouTube.
|
|||
|
|
2. После sync видит подписанные каналы.
|
|||
|
|
3. Может создать категорию.
|
|||
|
|
4. Может назначить каналу одну или несколько категорий.
|
|||
|
|
5. Может выбрать категорию и увидеть соответствующую video feed.
|
|||
|
|
6. Карточка показывает thumbnail/title/channel/time/duration.
|
|||
|
|
7. Можно открыть video page.
|
|||
|
|
8. Нескачанный ролик играет через YouTube.
|
|||
|
|
9. Работает Download.
|
|||
|
|
10. Отображаются queued/downloading/completed/failed.
|
|||
|
|
11. Completed ролик имеет статус `На сервере`.
|
|||
|
|
12. Completed ролик играет через MeTube local URL.
|
|||
|
|
13. Есть loading/error/empty states.
|
|||
|
|
14. UI usable на desktop и mobile.
|
|||
|
|
15. Browser refresh сохраняет route.
|
|||
|
|
16. UI не показывает secrets/internal paths/job IDs.
|
|||
|
|
17. На feed нет N+1 requests.
|
|||
|
|
18. Основной экран воспринимается как видеоприложение, а не административная панель.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 35. Главное UX-правило
|
|||
|
|
|
|||
|
|
Пользователь должен воспринимать сервис так:
|
|||
|
|
|
|||
|
|
> Это моя лента YouTube-подписок, только каналы нормально разложены по темам, а понравившееся видео я могу одним кликом оставить у себя.
|
|||
|
|
|
|||
|
|
Технические детали:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
OAuth
|
|||
|
|
YouTube Data API
|
|||
|
|
PostgreSQL
|
|||
|
|
MeTube
|
|||
|
|
Socket.IO
|
|||
|
|
mediaVM
|
|||
|
|
filenames
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
должны быть скрыты за простым интерфейсом.
|