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)
This commit is contained in:
@@ -132,20 +132,23 @@ filmstrip, панель метаданных/комментариев, тулб
|
||||
панель обходилась одним запросом. Переименование публикует `photo.updated`, страница альбома
|
||||
обновляет запись в списке.
|
||||
|
||||
### 17. Настройки информации: оверрайды в профиле пользователя
|
||||
Настройки раздела «Информация» хранятся в профиле как оверрайды, а не как полный список:
|
||||
### 17. Настройки информации: явный список видимых в профиле пользователя
|
||||
Настройки раздела «Информация» хранятся в профиле как явный список видимых атрибутов:
|
||||
`users.preferences` (jsonb, дефолт `{}`) с секцией `photo_info` вида
|
||||
`{ "hidden": ["Contrast", ...], "labels": { "Make": "Камера", ... } }`. Отсутствие ключа
|
||||
означает, что атрибут видим и подпись дефолтная, поэтому новые и незнакомые теги EXIF не
|
||||
«теряются» и не требуют миграций данных. `GET /auth/me` отдаёт `preferences` вместе с
|
||||
пользователем; сохранение — `PATCH /auth/me/preferences` (полная замена объекта с серверной
|
||||
валидацией: строки и массивы строк, ограничение длины подписи/ключа и числа скрытых ключей).
|
||||
Настройки не входят в `PublicUser` (приватны). UI: `PanelSection` получает слот `actions` под
|
||||
шестерёнку; модалка `PhotoInfoSettingsDialog` строится из объединения известного каталога
|
||||
подписей и ключей текущего фото; список в панели фильтруется по оверрайдам, а скрытые
|
||||
атрибуты сворачиваются под кнопку «…» (раскрытие — временное, для текущего фото).
|
||||
Альтернативы: полный упорядоченный список в профиле (хрупок к новым тегам, нужны миграции) и
|
||||
хранение на клиенте (не переносится между устройствами) — отклонены.
|
||||
`{ "visible": ["Make", "Model", ...], "labels": { "Make": "Камера", ... } }`. Отсутствие
|
||||
секции `photo_info` означает базовый набор по умолчанию (камера, объектив, выдержка,
|
||||
диафрагма, ISO, фокусное расстояние) — не «все атрибуты». Список `visible` хранится явно,
|
||||
поэтому различимо состояние «ничего не выбрано»; новые и незнакомые теги не «теряются» (их
|
||||
можно включить в диалоге). `GET /auth/me` отдаёт `preferences` вместе с пользователем;
|
||||
сохранение — `PATCH /auth/me/preferences` (полная замена объекта с серверной валидацией:
|
||||
строки и массивы строк, ограничение длины подписи/ключа и числа записей). Пустой объект
|
||||
(`{}`) удаляет настройки, возвращая базовый набор. Настройки не входят в `PublicUser`
|
||||
(приватны). UI: `PanelSection` получает слот `actions` под шестерёнку; модалка
|
||||
`PhotoInfoSettingsDialog` строится из объединения известного каталога подписей и ключей
|
||||
текущего фото и даёт действия «отметить все»/«снять все» и «Сбросить»; список в панели
|
||||
фильтруется по сохранённым видимым атрибутам, а остальные сворачиваются под кнопку «…»
|
||||
(раскрытие — временное, для текущего фото). Альтернатива с оверрайдами `hidden` (пусто = все
|
||||
видимы) отклонена: не даёт базовый набор по умолчанию.
|
||||
|
||||
### 18. Метаданные фото: устойчивый парсер и хранение в jsonb
|
||||
EXIF извлекается при загрузке и хранится в `photos.exif` (jsonb, миграция `000003_photo_exif`)
|
||||
|
||||
Reference in New Issue
Block a user