Files
ds-galo/openspec/specs/ui-workspace/spec.md
iu 384f126d8a chore(openspec): archive lightroom-workspace-ui and sync main specs
- synced delta specs into main specs: albums (+3 reqs, MODIFIED deleting album -> photos to trash), auth (+1), photos (+8), and created new ui-workspace spec (29 reqs)
- moved the change to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/
2026-10-10 22:47:33 +03:00

385 lines
29 KiB
Markdown

# ui-workspace Specification
## Purpose
Рабочий стол веб-приложения: постоянный каркас с рейлом альбомов, контекстной панелью,
режимом просмотра фото и адаптивным поведением, обеспечивающий цельный «lightroom»-вид.
## Requirements
### Requirement: Рабочий стол приложения
Аутентифицированные экраны SHALL отображаться внутри постоянного каркаса с топбаром, левым
рейлом альбомов и контекстной правой панелью. Публичные экраны (вход, инвайт, share-ссылка)
SHALL отображаться вне каркаса, но в общей теме оформления.
#### Scenario: Внутренний экран
- **WHEN** аутентифицированный пользователь открывает список альбомов или альбом
- **THEN** экран отрисован внутри каркаса с рейлом и панелью, рейл не перезагружается при переходе
#### Scenario: Публичный экран
- **WHEN** пользователь открывает публичную share-ссылку без входа
- **THEN** экран отрисован без рейла и контекстной панели, но в тех же цветовых токенах
### Requirement: Рейл альбомов
Рейл SHALL постоянно показывать список доступных альбомов с их обложками и отмечать
активный альбом.
#### Scenario: Активный альбом
- **WHEN** пользователь находится в альбоме
- **THEN** соответствующий элемент рейла выделен, остальные показывают обложки или плейсхолдер
### Requirement: Создание альбома
Создание альбома SHALL выполняться через иконочную кнопку с подсказкой, открывающую
модальное окно ввода названия, вместо инлайн-формы.
#### Scenario: Создание через модалку
- **WHEN** пользователь нажимает кнопку создания, вводит название и подтверждает
- **THEN** система создаёт альбом и делает его активным
#### Scenario: Пустое название
- **WHEN** пользователь подтверждает пустое название
- **THEN** создание не выполняется
### Requirement: Контекстная панель альбома
Правая панель SHALL показывать превью обложки, название, счётчики фото и участников,
управление обложкой и переходы к участникам, настройкам и ссылкам. Элементы управления
обложкой SHALL быть доступны только owner и admin.
#### Scenario: Владелец альбома
- **WHEN** owner открывает альбом
- **THEN** панель показывает управление обложкой и переходы к участникам и настройкам
#### Scenario: Наблюдатель
- **WHEN** viewer открывает альбом
- **THEN** панель не показывает управление обложкой
### Requirement: Режим просмотра фотографии
Просмотр фото SHALL быть отдельным маршрутом внутри каркаса с крупным изображением,
лентой миниатюр снизу и панелью метаданных и комментариев. Тот же режим SHALL
использоваться на публичных share-страницах.
#### Scenario: Открытие фото
- **WHEN** пользователь выбирает фото в сетке
- **THEN** открывается маршрут фото в каркасе, рейл и панель остаются доступны, адрес отражает фото
#### Scenario: Навигация в просмотре
- **WHEN** пользователь использует стрелки влево/вправо или ленту миниатюр
- **THEN** показывается соседнее фото, адрес обновляется
#### Scenario: Публичный просмотр
- **WHEN** посетитель share-ссылки открывает фото
- **THEN** используется тот же режим просмотра без рейла и панели
### Requirement: Плотность сетки
Сетка SHALL давать пользователю управлять размером миниатюр, и выбранный размер SHALL
сохраняться между сессиями.
#### Scenario: Изменение размера
- **WHEN** пользователь двигает регулятор плотности
- **THEN** размер миниатюр меняется, значение сохраняется и восстанавливается при следующем открытии
### Requirement: Загрузка фотографий из рабочего стола
Загрузка SHALL запускаться действием в тулбаре; перетаскивание файлов над альбомом SHALL
показывать оверлей и загружать их; пустой альбом SHALL показывать подсказку-зону загрузки.
Загрузка SHALL быть доступна только ролям с правом загрузки.
#### Scenario: Перетаскивание
- **WHEN** пользователь с правом загрузки перетаскивает файлы над альбомом
- **THEN** показывается оверлей загрузки, и файлы загружаются
#### Scenario: Пустой альбом
- **WHEN** пользователь открывает альбом без фото и имеет право загрузки
- **THEN** в центре показана зона-подсказка загрузки
### Requirement: Темы и графитовый хром
Тёмная тема SHALL использовать графитовый хром Lightroom и SHALL применяться по умолчанию;
нейтральная тема SHALL быть тёплым графитом; остальные темы SHALL оставаться доступными, а
скроллбары SHALL быть стилизованы в цвет темы.
#### Scenario: Первый вход
- **WHEN** пользователь впервые открывает приложение без сохранённой темы
- **THEN** применяется тёмная графитовая тема
#### Scenario: Смена темы
- **WHEN** пользователь выбирает другую тему
- **THEN** интерфейс, иконки и скроллбары меняются согласованно, и выбор сохраняется
#### Scenario: Нейтральная тема
- **WHEN** пользователь выбирает нейтральную тему
- **THEN** применяется тёплый графитовый хром, отличный от холодной тёмной темы
### Requirement: Адаптивность рабочего стола
На узких экранах рейл SHALL становиться выдвижной панелью, контекстная панель —
сворачиваемой секцией, а лента миниатюр — горизонтально прокручиваемой.
#### Scenario: Узкий экран
- **WHEN** ширина окна меньше порога рабочего стола
- **THEN** рейл скрыт за кнопкой открытия, панель сворачиваема, лента прокручивается горизонтально
### Requirement: Доступность рабочего стола
Иконочные органы управления каркаса SHALL иметь доступные имена, панели SHALL быть
достижимы с клавиатуры с видимым фокусом, анимации SHALL учитывать
предпочтение уменьшенного движения.
#### Scenario: Клавиатурная навигация
- **WHEN** пользователь работает только с клавиатуры
- **THEN** органы управления каркаса достижимы, доступные имена присутствуют, фокус виден
### Requirement: Изменение ширины панелей
Пользователь SHALL иметь возможность менять ширину левой и правой панелей перетаскиванием, а
выбранная ширина SHALL сохраняться между сессиями.
#### Scenario: Перетаскивание разделителя
- **WHEN** пользователь тянет разделитель у панели на рабочем столе
- **THEN** панель меняет ширину в допустимых пределах
#### Scenario: Сохранение ширины
- **WHEN** пользователь перезагружает приложение
- **THEN** восстановленные панели имеют сохранённую ширину
### Requirement: Сворачиваемые разделы панели
Контекстная панель SHALL группировать содержимое в сворачиваемые разделы, а состояние
сворачивания SHALL сохраняться; раздел «Информация» SHALL показывать метаданные фото,
включая извлечённые EXIF-атрибуты.
#### Scenario: Сворачивание раздела
- **WHEN** пользователь нажимает заголовок раздела
- **THEN** содержимое раздела скрывается или показывается, состояние сохраняется
#### Scenario: Метаданные фото
- **WHEN** открыт просмотр фото
- **THEN** раздел «Информация» показывает размер, тип, разрешение, дату съёмки, координаты и извлечённые EXIF-атрибуты
### Requirement: Полноэкранный просмотр фотографии
В режиме просмотра SHALL быть доступен переход в полноэкранный режим кнопкой и хоткеем `f`.
В полноэкранном режиме верхняя и нижняя панели SHALL скрываться и показываться у
соответствующей кромки экрана.
#### Scenario: Вход в полный экран
- **WHEN** пользователь нажимает кнопку полного экрана или клавишу `f`
- **THEN** просмотр разворачивается на весь экран, панели скрыты
#### Scenario: Панель по кромке
- **WHEN** курсор касается верхней или нижней кромки экрана
- **THEN** соответствующая панель показывается, а при уходе курсора скрывается сразу
#### Scenario: Выход из полного экрана
- **WHEN** пользователь повторно нажимает кнопку или клавишу `f`
- **THEN** полноэкранный режим закрывается
#### Scenario: Полноэкранный режим приложения
- **WHEN** включён полноэкранный режим приложения, и пользователь нажимает `f`
- **THEN** открывается полноэкранный просмотр фото (вложенно), а полноэкранный режим приложения не выключается
### Requirement: Зум в просмотре
Просмотр SHALL поддерживать зум колесом мыши без прокрутки, с привязкой к указателю и
верхним пределом 200% размеров фото. `Space` SHALL возвращать изображение из любого зума во
вписанный вид, а из вписанного — в 100%. При зуме SHALL догружаться оригинал изображения.
Стрелки соседних фото SHALL появляться у левой/правой кромки и прятаться в зуме. Зум SHALL
работать и в полноэкранном режиме.
#### Scenario: Зум колесом к указателю
- **WHEN** пользователь вращает колесо мыши над фото
- **THEN** масштаб меняется относительно курсора, страница не прокручивается, предел — 200%
#### Scenario: Пробел
- **WHEN** пользователь нажимает `Space`
- **THEN** из вписанного вида изображение переходит в 100%, а из любого зума возвращается во вписанный
#### Scenario: Оригинал в зуме
- **WHEN** пользователь входит в зум
- **THEN** догружается оригинал изображения и подменяется по факту загрузки
#### Scenario: Стрелки соседних фото
- **WHEN** курсор находится у левой или правой кромки области просмотра
- **THEN** показывается соответствующая стрелка, скрываясь сразу после ухода; в зуме стрелки скрыты
#### Scenario: Панорамирование
- **WHEN** фото увеличено
- **THEN** пользователь может перемещать изображение перетаскиванием и прокруткой
### Requirement: Удаление фото из просмотра
Автор фото, владелец и админ альбома SHALL иметь возможность удалить текущее фото из режима
просмотра; удаление SHALL подтверждаться диалогом.
#### Scenario: Подтверждение удаления
- **WHEN** пользователь с правом удаления нажимает «Удалить»
- **THEN** открывается диалог подтверждения, и после подтверждения фото удаляется
#### Scenario: Лента после удаления
- **WHEN** фото удалено
- **THEN** просмотр переходит к соседнему фото, а лента миниатюр обновляется без удалённого
### Requirement: Возврат к обзору
Из альбома и из режима просмотра SHALL быть доступен возврат к обзору альбомов.
#### Scenario: Возврат из альбома
- **WHEN** пользователь нажимает кнопку «назад» слева от названия альбома
- **THEN** открывается обзор альбомов
#### Scenario: Возврат из просмотра
- **WHEN** пользователь нажимает кнопку «назад» в режиме просмотра
- **THEN** открывается альбом с сеткой фото
### Requirement: Настройки списка атрибутов информации
Раздел «Информация» SHALL предоставлять доступ к настройкам (иконка-шестерёнка), открывающим
модальное окно со списком EXIF-атрибутов, где пользователь SHALL отмечать отображаемые
атрибуты и задавать их подписи. В окне SHALL быть доступны действия «отметить все» и
«снять все». Настройки SHALL применяться ко всем фото и SHALL сохраняться в профиле
пользователя. При отсутствии сохранённых настроек SHALL отображаться базовый набор атрибутов
(камера, объектив, выдержка, диафрагма, ISO, фокусное расстояние).
#### Scenario: Открытие настроек
- **WHEN** пользователь нажимает иконку настроек в разделе «Информация»
- **THEN** открывается модальное окно со списком EXIF-атрибутов: галочки видимости и поля подписей, а также действия «отметить все»/«снять все»
#### Scenario: Значения по умолчанию
- **WHEN** у пользователя нет сохранённых настроек
- **THEN** в разделе «Информация» показан базовый набор атрибутов, а остальные доступны по элементу «…»
#### Scenario: Сохранение настроек
- **WHEN** пользователь отмечает атрибуты, задаёт подпись и сохраняет
- **THEN** раздел «Информация» учитывает изменения, а настройки сохраняются в профиле
#### Scenario: Сброс настроек
- **WHEN** пользователь сбрасывает настройки
- **THEN** сохранённые настройки удаляются из профиля, и отображается базовый набор с исходными подписями
### Requirement: Свёртка скрытых атрибутов
Если настройками часть атрибутов скрыта, в конце списка атрибутов SHALL отображаться элемент
«…»; нажатие на него SHALL раскрывать все атрибуты текущего фото, включая скрытые. Если
скрытых атрибутов нет, элемент «…» SHALL не отображаться.
#### Scenario: Скрытые атрибуты
- **WHEN** в разделе «Информация» есть скрытые настройками атрибуты
- **THEN** после видимых атрибутов показан элемент «…»
#### Scenario: Раскрытие всех атрибутов
- **WHEN** пользователь нажимает «…»
- **THEN** отображаются все атрибуты фото, включая скрытые
#### Scenario: Нет скрытых атрибутов
- **WHEN** ни один атрибут не скрыт
- **THEN** элемент «…» не отображается
### Requirement: Выбор фото в сетке
В режиме альбома одиночный выбор фото SHALL отмечать его рамкой и показывать его сведения в
контекстной панели, не открывая просмотр; двойной выбор SHALL открывать режим просмотра фото.
#### Scenario: Одиночный выбор
- **WHEN** пользователь кликает по фото в сетке
- **THEN** фото отмечено рамкой, правая панель показывает сведения об этом фото, просмотр не открывается
#### Scenario: Двойной выбор
- **WHEN** пользователь дважды кликает по фото в сетке
- **THEN** открывается режим просмотра этого фото
#### Scenario: Смена альбома
- **WHEN** пользователь переходит в другой альбом
- **THEN** отметка выбора сбрасывается
### Requirement: Мультивыбор фото в сетке
В режиме альбома пользователь SHALL выбирать несколько фото: обычный клик — одно фото,
Ctrl/Cmd-клик — добавить или убрать, Shift-клик — диапазон. Выбранные фото SHALL быть отмечены.
#### Scenario: Мультивыбор
- **WHEN** пользователь кликает по фото с зажатым Ctrl/Cmd или Shift
- **THEN** соответствующие фото отмечены, а панель показывает количество выбранных
### Requirement: Действия с выбранными фото
Когда выбрано одно или несколько фото, правая панель SHALL показывать раздел «Действия» со
строками-пунктами (иконка + подпись) «Открыть (просмотр)», «Переместить», «Копировать» и
«Удалить»; удаление SHALL подтверждаться диалогом.
#### Scenario: Действия
- **WHEN** выбрано одно или несколько фото
- **THEN** панель показывает раздел «Действия» с пунктами «Открыть (просмотр)», «Переместить», «Копировать» и «Удалить»
### Requirement: Перетаскивание выбранных фото на альбом
Выбранные фото SHALL перетаскиваться на альбом в рейле; при отпускании SHALL открываться
диалог выбора переноса или копирования с указанием целевого альбома. Во время такого
перетаскивания зона загрузки файлов SHALL не показываться.
#### Scenario: Перетаскивание на альбом
- **WHEN** пользователь перетаскивает выделенные фото на альбом в рейле и отпускает
- **THEN** открывается диалог с выбором переноса/копирования и целевым альбомом
### Requirement: Корзина в списке альбомов
Рейл альбомов SHALL содержать вход в корзину последним элементом списка (с иконкой корзины).
Экран обзора альбомов SHALL не показывать пустую правую панель.
#### Scenario: Вход в корзину
- **WHEN** пользователь открывает приложение
- **THEN** в левом рейле последним элементом списка показана «Корзина» с иконкой корзины
#### Scenario: Обзор без панели
- **WHEN** пользователь открывает обзор альбомов
- **THEN** правая панель не отображается
### Requirement: Действия в режиме просмотра
В режиме просмотра правая панель SHALL содержать раздел «Действия» со строками-пунктами
(иконка + подпись) «Скачать», «Переместить», «Копировать» и «Удалить» (удаление — по правам).
Верхняя панель просмотра SHALL не дублировать скачивание и удаление.
#### Scenario: Действия в просмотре
- **WHEN** открыт режим просмотра фото
- **THEN** раздел «Действия» содержит «Скачать», «Переместить», «Копировать» и «Удалить», а в верхней панели этих кнопок нет
#### Scenario: Удаление из панели
- **WHEN** пользователь удаляет фото из раздела «Действия»
- **THEN** открывается подтверждение, и после удаления просмотр переходит к соседнему фото
### Requirement: Контекстное меню фото
Правый клик по фото в сетке и по изображению в режиме просмотра SHALL открывать контекстное
меню с пунктами раздела «Действия» («Скачать», «Переместить», «Копировать», «Удалить»; в сетке
также «Открыть (просмотр)»), выполняющими те же действия.
#### Scenario: Меню в сетке
- **WHEN** пользователь кликает правой кнопкой по фото в сетке
- **THEN** открывается меню с пунктами «Открыть (просмотр)», «Скачать», «Переместить», «Копировать», «Удалить»
#### Scenario: Меню в просмотре
- **WHEN** пользователь кликает правой кнопкой по изображению в режиме просмотра
- **THEN** открывается меню с пунктами «Скачать», «Переместить», «Копировать», «Удалить»
### Requirement: Контекстное меню альбома
Правый клик по альбому в рейле и по карточке на обзоре SHALL открывать меню с пунктами
«Переименовать» и «Удалить»; переименование SHALL открывать диалог, удаление — подтверждение.
#### Scenario: Меню альбома
- **WHEN** пользователь кликает правой кнопкой по альбому
- **THEN** открывается меню с «Переименовать» и «Удалить»
#### Scenario: Удаление альбома
- **WHEN** пользователь подтверждает удаление альбома
- **THEN** альбом удаляется, а его фото попадают в корзину
### Requirement: Счётчики в рейле
Рейл SHALL показывать число фото у каждого альбома и число элементов в корзине.
#### Scenario: Счётчики
- **WHEN** пользователь смотрит на рейл альбомов
- **THEN** у каждого альбома показано число фото, а у корзины — число удалённых фото
### Requirement: Метки в панели фото
Панель фото SHALL содержать раздел «Метки» с чипами меток фото и полем добавления, дающим
поиск по меткам пользователя и создание новых.
#### Scenario: Раздел «Метки»
- **WHEN** открыт просмотр или выбран один фото в сетке
- **THEN** в панели есть раздел «Метки» с текущими метками и полем добавления с поиском
### Requirement: Компактный верхний хром
Верхняя панель приложения и верхняя панель режима просмотра SHALL иметь минимальную высоту
(узкие отступы, иконочные органы управления), сохраняя все действия доступными. Верхняя панель
режима просмотра SHALL быть прозрачным оверлеем и SHALL не занимать место в раскладке,
увеличивая область фото.
#### Scenario: Компактные верхние панели
- **WHEN** открыт список альбомов или режим просмотра фото
- **THEN** верхняя панель занимает минимум высоты, а её действия (навигация, полный экран, скачивание, удаление) доступны
#### Scenario: Прозрачная панель просмотра
- **WHEN** открыт режим просмотра фото
- **THEN** верхняя панель нарисована поверх фото без фона и не уменьшает область изображения