Files
ds-galo/openspec/changes/lightroom-workspace-ui/specs/ui-workspace/spec.md
T
iu 1b4906648d feat(preferences): configurable photo info attributes stored in user profile
- backend: users.preferences jsonb (migration 000004), Me returns preferences, PATCH /auth/me/preferences with validation (visible list + labels)
- frontend: gear in info section opens PhotoInfoSettingsDialog; base attribute set shown by default, remaining under ellipsis; per-attribute visibility and custom labels persisted to the profile; reset clears settings from the profile
- frontend: dialog has select-all/deselect-all icon buttons (no 'show all'); EXIF constants extracted to lib/exif.ts
- fix: render modal overlays via portal to document.body so they center in the viewport despite transformed panel/rail ancestors
- openspec: sync lightroom-workspace-ui artifacts (spec/design/proposal/tasks 9.8)
2026-10-10 21:04:08 +03:00

19 KiB

Spec Delta

Purpose

Рабочий стол веб-приложения: постоянный каркас с рейлом альбомов, контекстной панелью, режимом просмотра фото и адаптивным поведением, обеспечивающий цельный «lightroom»-вид.

ADDED 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 полноэкранный режим закрывается

Requirement: Зум в просмотре

Просмотр SHALL поддерживать зум колесом мыши без прокрутки, с привязкой к указателю и верхним пределом 200% размеров фото. Space SHALL возвращать изображение из любого зума во вписанный вид, а из вписанного — в 100%. При зуме SHALL догружаться оригинал изображения. Стрелки соседних фото SHALL появляться у левой/правой кромки и прятаться в зуме. Зум SHALL работать и в полноэкранном режиме.

Scenario: Зум колесом к указателю

  • WHEN пользователь вращает колесо мыши над фото
  • THEN масштаб меняется относительно курсора, страница не прокручивается, предел — 200%

Scenario: Пробел

  • WHEN пользователь нажимает Space
  • THEN из вписанного вида изображение переходит в 100%, а из любого зума возвращается во вписанный

Scenario: Оригинал в зуме

  • WHEN пользователь входит в зум
  • THEN догружается оригинал изображения и подменяется по факту загрузки

Scenario: Стрелки соседних фото

  • WHEN курсор находится у левой или правой кромки области просмотра
  • THEN показывается соответствующая стрелка, скрываясь примерно через 300 мс после ухода; в зуме стрелки скрыты

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 элемент «…» не отображается