Рабочий стол приложения в духе Adobe Lightroom: постоянный рейл альбомов, контекстная правая панель, плотная сетка, режим просмотра как часть рабочего стола, обложки с явным выбором и единый тёмный графитовый хром.
Основное:
Рабочий стол (шелл). Группа (app) с постоянным левым рейлом альбомов, топбаром и контекстной правой панелью; публичные маршруты (/login, /invites/[token], /share/[token]) остаются вне шелла.
Обложки.Album.cover_thumb_url, реальные миниатюры в карточках и рейле, пикер обложки в правой панели, FK albums.cover_photo_id -> photos(id) ON DELETE SET NULL.
Просмотр как маршрут.Lightbox-оверлей заменён маршрутом /albums/:id/photos/:photoId; полноэкранный режим, зум колесом к указателю, догрузка оригинала.
EXIF. Извлечение метаданных при загрузке в photos.exif, команда бэкфилла cmd/backfill-exif, раздел «Информация» с настраиваемыми атрибутами в профиле пользователя.
Метки фото, контекстные меню, удаление в корзину, перенос/копирование, счётчики фото и участников.
Плотность сетки, мультивыбор, адаптив (off-canvas рейл, bottom-sheet панель).
API-контракты сохраняются; ломающих изменений API нет.
Открытые изменения OpenSpec заархивированы, основные спеки синхронизированы.
## Что сделано
Рабочий стол приложения в духе Adobe Lightroom: постоянный рейл альбомов, контекстная правая панель, плотная сетка, режим просмотра как часть рабочего стола, обложки с явным выбором и единый тёмный графитовый хром.
Основное:
- **Рабочий стол (шелл).** Группа `(app)` с постоянным левым рейлом альбомов, топбаром и контекстной правой панелью; публичные маршруты (`/login`, `/invites/[token]`, `/share/[token]`) остаются вне шелла.
- **Обложки.** `Album.cover_thumb_url`, реальные миниатюры в карточках и рейле, пикер обложки в правой панели, FK `albums.cover_photo_id -> photos(id) ON DELETE SET NULL`.
- **Просмотр как маршрут.** `Lightbox`-оверлей заменён маршрутом `/albums/:id/photos/:photoId`; полноэкранный режим, зум колесом к указателю, догрузка оригинала.
- **EXIF.** Извлечение метаданных при загрузке в `photos.exif`, команда бэкфилла `cmd/backfill-exif`, раздел «Информация» с настраиваемыми атрибутами в профиле пользователя.
- **Метки фото, контекстные меню, удаление в корзину, перенос/копирование, счётчики** фото и участников.
- **Плотность сетки, мультивыбор, адаптив** (off-canvas рейл, bottom-sheet панель).
- **Темы.** `dark` — графит Lightroom и дефолт, `neutral` — тёплый графит; токены `--chrome`/`--canvas`; стилизованные скроллбары.
## Спеки
- `ui-workspace` (новая)
- `albums`, `photos`, `auth` (дельты)
## Заметки
- API-контракты сохраняются; ломающих изменений API нет.
- Открытые изменения OpenSpec заархивированы, основные спеки синхронизированы.
Backend:
- expose cover thumbnail URL on album responses (LEFT JOIN + presign)
- auto-assign cover only when empty; FK cover_photo_id -> photos ON DELETE SET NULL
- add photos_count / members_count to album responses; cover repo test
Frontend:
- split layouts into (app) shell (resizable rail + contextual panel) and (public)
- album rail + create-album dialog; album panel with cover picker / make-cover
- photo viewer route with filmstrip, replacing lightbox; share reuses it
- grid density slider, toolbar + drag-and-drop upload, dark graphite default
OpenSpec: add lightroom-workspace-ui change (proposal, design, specs, tasks)
- add fullscreen/fullscreen_exit icons and a top-bar toggle (right of themes)
- add back arrow left of the album title to return to the albums overview
Backend:
- add PATCH /api/photos/:id to rename original_filename (uploader/owner/admin)
- emit photo.updated SSE event
Frontend:
- inline filename editor in the right panel
- viewer: back button (arrow_back) on the left, delete on the right
- delete confirmed via a modal dialog; filmstrip updates after deletion
- add PanelSection with persisted collapse state
- restructure album and photo panels into sections
- add "Информация" section with EXIF/metadata (size, type, resolution, taken, coords)
- fullscreen toggle button + "f" hotkey (both layouts)
- wheel zoom anchored to cursor; Space toggles 100% (1:1)
- pan when zoomed via drag/scrollbars; reset zoom on photo change
- hotkeys ignored while typing in inputs
- raise upload limit to 100 MB
- return 413 file_too_large on MaxBytesError instead of misleading
"expected multipart form"
- client-side per-file and total size pre-check with a clear message
- fullscreen: auto-hide top toolbar and filmstrip, revealed at top/bottom
screen edge and hidden 1s after the cursor leaves
- arrows < >: edge-reveal in both normal and fullscreen; hide 300ms after
leaving; hidden while zoomed
- zoom: wheel zooms only (no scroll, overscroll contained), anchored to the
pointer, capped at 200%; Space toggles 100%/fit; pan via drag/scroll
Reflect post-planning work in proposal, design, specs (albums/photos/
ui-workspace) and tasks: photo rename, viewer delete/zoom/fullscreen,
resizable and collapsible panels with EXIF, upload size limit, album
counts, themes/scrollbars, back navigation.
- in zoom, preload the full-resolution original and swap it in once loaded
(preview is shown until then); revert to preview on zoom exit
- Space returns to the fitted view from any zoom level; from fit it goes to 100%
- derive zoom scale from the photo's true dimensions so 100% is accurate
- backend: switch EXIF parser to dsoprea/go-exif/v3 (all recognised tags, numeric normalization); store in photos.exif jsonb (migration 000003); add storage.Get and cmd/backfill-exif to backfill existing photos from S3 originals
- frontend: info panel renders all EXIF attributes with RU labels, enum translation and units (1/N, f/N, mm, EV); service tags hidden
- viewer: remove make-cover action (cover managed from panel only), icon-only download
- openspec: sync lightroom-workspace-ui artifacts (EXIF, cover-from-panel) and add plan for configurable info attributes/labels 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)
- remove all hide timers in Viewer; top/bottom bars and arrows now show/hide immediately
- arrows reveal only within the viewer bounds (no longer stay visible when the pointer is over the left/right panels)
- f (and the viewer button) toggle the viewer's own fullscreen via nested fullscreen, so f works inside app-level fullscreen without turning it off
- single click selects a photo (ring + aria-pressed) and shows its info in the right panel without navigating; double click opens the viewer
- shared 'selection' store; panel uses the route photo in viewer mode and the selected photo in album mode; selection resets on album change
- openspec: sync lightroom-workspace-ui (grid-selection requirement, viewer chrome wording without timers, nested f fullscreen, tasks 9.9/9.10)
- backend: deleting an album moves its photos to the trash without losing files (photos.album_id nullable, FK ON DELETE SET NULL, migration 000006; dropped S3 prefix delete); restore accepts an album target (album_required when the album is gone); user-scoped tags (000007) with GET /tags, POST/DELETE /photos/:id/tags, tags included in photo responses; GET /trash/count
- frontend: right-click context menus for photos (grid + viewer) and albums (rail + overview); single shared PhotoPanel reused in viewer and gallery selection (not a copy); viewer download/delete moved to the panel 'Действия'; transparent compact viewer top bar; trash entry as last rail item with per-album photo counts and trash count; album rename/delete dialogs
- openspec: sync lightroom-workspace-ui artifacts (specs photos/ui-workspace, design #24-30, tasks 9.17-9.24)
- 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/
iu
merged commit 9effc0fc82 into develop2026-10-10 19:56:22 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Что сделано
Рабочий стол приложения в духе Adobe Lightroom: постоянный рейл альбомов, контекстная правая панель, плотная сетка, режим просмотра как часть рабочего стола, обложки с явным выбором и единый тёмный графитовый хром.
Основное:
(app)с постоянным левым рейлом альбомов, топбаром и контекстной правой панелью; публичные маршруты (/login,/invites/[token],/share/[token]) остаются вне шелла.Album.cover_thumb_url, реальные миниатюры в карточках и рейле, пикер обложки в правой панели, FKalbums.cover_photo_id -> photos(id) ON DELETE SET NULL.Lightbox-оверлей заменён маршрутом/albums/:id/photos/:photoId; полноэкранный режим, зум колесом к указателю, догрузка оригинала.photos.exif, команда бэкфиллаcmd/backfill-exif, раздел «Информация» с настраиваемыми атрибутами в профиле пользователя.dark— графит Lightroom и дефолт,neutral— тёплый графит; токены--chrome/--canvas; стилизованные скроллбары.Спеки
ui-workspace(новая)albums,photos,auth(дельты)Заметки
- backend: soft delete + trash (photos.deleted_at, migration 000005), GET /trash, restore, permanent delete with storage-key refcount (S3 objects removed only when no other album references them); batch endpoints photo-batch/{delete,move,copy} - metadata only, copies clone rows sharing storage keys - frontend: Ctrl/Shift multiselect; right-panel 'Действия' as icon text rows (Открыть (просмотр), Переместить, Копировать, Удалить); drag selected photos onto rail album -> TransferDialog; /trash route; trash entry as last item in the left rail; empty right panel hidden on overview - frontend: compact top bars (app header and viewer), compact theme switcher - openspec: sync lightroom-workspace-ui artifacts (photos/ui-workspace specs, design #20-24, tasks 9.11-9.17)