Commit Graph
39 Commits
Author SHA1 Message Date
iu 35f84399bc feat(web): зум клавишами + и - в просмотре фото
В режиме просмотра фотографии (обычный и полноэкранный) клавиши + и - меняют
масштаб изображения на шаг, сохраняя точку в центре просмотра. Пока открыт
просмотр, эти клавиши больше не меняют размер миниатюр в сетке.
2026-10-20 22:01:41 +03:00
iu 50b9983be4 feat(web): сохранять размер миниатюр при скрытых боковых панелях
В скрытом режиме панели больше не растягивают плитки: сетка пересчитывает
число колонок так, чтобы размер миниатюры остался прежним, а в строке
помещалось больше фото. Каркас публикует ширину, которую занимают панели в
текущей раскладке (рейл на широких экранах, панель на сверхшироких), сетка
использует её для пересчёта, а навигация курсора стрелками учитывает
реальное число колонок.
2026-10-20 21:38:02 +03:00
iu 45a953f8bb feat(web): скрытие боковых панелей в альбоме и хоткеи размера миниатюр
В режиме просмотра альбома добавлена кнопка скрытия левой и правой боковых
панелей (рядом с регулятором размера миниатюр) и хоткей Tab. В скрытом режиме
панели не занимают место в раскладке, а появляются по наведению на левую или
правую кромку окна и прячутся после ухода указателя.

Клавиши + и - меняют размер миниатюр на шаг, как кнопки регулятора; хоткей
работает на всех экранах приложения и не срабатывает при вводе текста, в
открытых диалогах и меню.

Спека ui-workspace дополнена требованиями о скрытии панелей и клавишах
изменения размера миниатюр.
2026-10-20 21:30:06 +03:00
iu e82f45647c feat(realtime): доставлять клиентам события жизненного цикла альбома и изменения состава фото
Публиковать album.created/updated/deleted и изменения состава фото в личный поток
SSE, а также photo.created при загрузке, чтобы списки альбомов, счётчики и открытые
страницы альбома обновлялись без перезагрузки.

- members.Repository получил Audience (владелец + участники) для дешёвого веера
- albums.Service рассылает события в личные потоки получателей, перечитывая альбом
  через GetByID и attachCover, чтобы payload совпадал с GET /api/albums
- members.Service публикует при принятии инвайта, смене роли и исключении
- photos.Service публикует photo.created при загрузке и album.updated при
  добавлении/копировании/перемещении/восстановлении/корзине/окончательном удалении
- photos_count теперь считает фото вне корзины
- web-клиент подписывается на /api/sse/me один раз на уровне layout'а (app) и
  применяет события к стору альбомов; страница альбома уходит при потере доступа
2026-10-15 23:25:07 +03:00
iu 04617d1cdb feat(profile): add round avatar with upload and cropping
- backend: user_avatar_objects binding (PG+SQLite), GC preserves avatar blobs,
  avatar service (EXIF-stripping WebP 128/512), public avatar read route
- web: avatar upload/crop on profile, round avatar in header/members/comments/author
- android: avatar upload/crop, round avatar on profile and albums header
- openspec: add-user-avatar proposal/design/specs/tasks
2026-10-12 16:16:47 +03:00
iu 86aff695df feat(auth): add user profile, phone login, and account deletion 2026-10-12 14:26:32 +03:00
iu 713c1ca6d3 fix(ui): keep trash counter in sync with trash changes
Reload the rail trash count after every operation that changes the
trash contents, not just navigation and empty-trash: moving photos to
trash (grid, panel, viewer), restoring, permanent delete and deleting
an album. Previously the counter stayed stale until the next route
change.
2026-10-12 12:58:18 +03:00
iu e4975aafb5 fix(ui): propagate photo tag edits to grid and viewer
Add a shared photo-updates signal the panel publishes on rename or tag
add/remove; the album grid and viewer subscribe and patch the changed
photo into their lists, so the 360 badge and panorama mode update without
a reload.
2026-10-12 12:14:48 +03:00
iu 6528abad82 fix(ui): correct horizontal drag direction in 360 panorama viewer
The panorama viewer inverted horizontal drag relative to vertical: the
yaw sign was opposite, so dragging right turned the view right instead
of moving the scene right. Flip yaw to match the pitch convention
(drag the world) and lock the behavior with a ui-workspace scenario.
2026-10-11 21:02:01 +03:00
iu 3b745fa737 feat(photos): fix trash permanent delete and add empty trash
Permanently deleting a photo whose album was deleted failed because
authorization resolved through the album. Fall back to uploader
ownership when the photo is albumless. Add a bulk DELETE /trash that
removes every trashed photo the caller may delete (uncapped listing)
and returns the deleted count, with an «Очистить корзину» action on the
trash screen.
2026-10-11 20:54:54 +03:00
iu d38ede0201 feat(video): add video upload with remux/transcode playback
Add video as a media kind in photos: streaming upload with per-kind
limits, ffprobe metadata, poster frame reusing the image variant
pipeline, and a playback object (remux when web-compatible, else
h264/yuv420p/aac transcode). Video jobs run on a separate pool with a
long lease. Frontend gains a video viewer, grid badge/duration and
video upload.
2026-10-11 20:37:53 +03:00
iu f1b3b01bdf feat(photos): add square medium variant for sharp grid thumbnails 2026-10-11 19:57:00 +03:00
iu 511de4ec9c fix(ui): use minus/plus icons for thumbnail size step buttons 2026-10-11 18:24:35 +03:00
iu 41e5dfaeb1 feat(ui): fix thumbnail size slider direction and add step buttons 2026-10-11 18:21:47 +03:00
iu a7867054a4 feat(ui): hover zoom on viewer thumbnail strip
- Thumbnails scale their image on pointer hover and keyboard focus
- Tile size and strip layout stay unchanged
2026-10-11 18:09:54 +03:00
iu ebae341c9a feat(ui): open photo on tap for touch and fix narrow-screen panel
- Touch/pen tap opens the viewer; mouse click still selects, dblclick opens
- Panel and rail emit a single transform utility so the panel actually
  slides in below 1280px (Tailwind v4 utility ordering made the base
  translate-x-full win over the conditional translate-x-0)
- Add touch-action: manipulation to grid cells
2026-10-11 17:58:04 +03:00
iu fc4233cd57 feat(ui): 360 panorama viewer by pano360 tag
- Detect 'pano360' tag and open the photo in a spherical viewer
- Mini-WebGL equirect viewer (no deps): drag to look, wheel FOV, Space reset
- Load original as origin-clean bitmap; fall back to flat image without WebGL
- 360 indicator in viewer and badge on grid tiles
2026-10-11 17:41:28 +03:00
iu 7359495a73 feat(ui): keyboard navigation and focus restore in album grid
- Cursor separate from selection; arrow keys move it, Space/Shift+Arrow/Enter/Esc act
- Click on empty grid space clears selection back to album properties
- Focus returns to the last viewed photo after closing the viewer
2026-10-11 14:51:00 +03:00
iu d7a37328f0 fix(photos): faster large-album loading and album cover lifecycle
Large albums opened slowly and flickered; the default album cover was
also lost in the media-objects refactor.

Large-album loading:
- quantize signed object URLs within a window and send Cache-Control so
  previews are reused instead of re-fetched
- publish photo.updated (not photo.created) when variants are ready, so
  clients update in place without reordering the grid
- worker concurrency + newest-first variant priority; raise default batch

Album cover:
- first uploaded photo becomes the cover when none is set
- clear the cover when the cover photo is trashed or moved out
- "set as album cover" in the photo context menu and actions panel

OpenSpec changes: fix-large-album-load, fix-album-cover
2026-10-11 14:15:59 +03:00
iu a5d0cee0eb feat(ui): link album rail title to overview 2026-10-11 13:27:39 +03:00
iu 50dff63ece feat: rename service to galo, add halo branding and release build
- rename Go module, binary, systemd unit, PG_DATABASE default, frontend package and docs from shared-album to galo
- add theme-aware halo emblem and favicon (new ui-branding capability)
- add make build-release (versioned, stripped, static binary) and run the binary from the repo root
2026-10-11 11:36:56 +03:00
iu 61b45b2742 feat: context menus, unified photo panel, tags, album trash and counters
- 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)
2026-10-10 22:45:41 +03:00
iu 2d6a3fea1a feat: photo multiselect, move/copy, trash and compact chrome
- 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)
2026-10-10 22:13:17 +03:00
iu 78996bc053 feat(frontend): select photo in album grid and show info in panel
- 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)
2026-10-10 21:33:59 +03:00
iu 642e3bcf8a fix(frontend): immediate viewer chrome and correct f fullscreen
- 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
2026-10-10 21:26:46 +03:00
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
iu e1592549b2 feat(photos): full EXIF metadata extraction, backfill and info panel
- 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
2026-10-10 20:31:34 +03:00
iu d8da885020 feat(frontend): viewer zoom loads original and Space resets to fit
- 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
2026-10-10 19:55:10 +03:00
iu d1e3aa85b4 feat(frontend): viewer fullscreen chrome and pointer-accurate zoom
- 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
2026-10-10 19:45:55 +03:00
iu b968248e3d style(frontend): theme-aware scrollbars
Thin scrollbars; thumb uses --border (hover --text-subtle), transparent
track. WebKit + Firefox, follows the active theme.
2026-10-10 19:45:55 +03:00
iu b02b165b3d fix(upload): clear error and higher limit for large files
- 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
2026-10-10 19:15:43 +03:00
iu 3886cc6511 feat(frontend): photo viewer fullscreen and zoom
- 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
2026-10-10 19:15:43 +03:00
iu b901544dc5 feat(frontend): collapsible right-panel sections with photo info
- add PanelSection with persisted collapse state
- restructure album and photo panels into sections
- add "Информация" section with EXIF/metadata (size, type, resolution, taken, coords)
2026-10-10 19:15:39 +03:00
iu aa396bdb85 feat: photo rename and viewer delete with confirmation
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
2026-10-10 18:50:16 +03:00
iu 1f0e909ffd feat(frontend): darken neutral theme and reorder theme switcher
- make neutral theme a warm dark graphite
- order switches as dark -> neutral -> light -> system
- replace neutral icon with contrast glyph
2026-10-10 18:36:32 +03:00
iu ba605402ce feat(frontend): fullscreen toggle and album back button
- 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
2026-10-10 18:28:56 +03:00
iu 304cfedb75 feat: lightroom-style workspace UI with album covers
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)
2026-10-10 18:15:13 +03:00
iu 997ec5e6c1 feat(frontend): replace emoji with inline Material Symbols icon system
Add a self-contained icon system: vendored Material Symbols registry, an
<Icon> component that references a single <symbol> sprite via <use>, plus
IconButton/IconSprite. Replace every emoji/Unicode glyph (logo, theme
switcher, cover placeholder, like/comment counts, lightbox controls, back
links) and add leading icons to key controls. Decorative icons are
aria-hidden; icon-only buttons get labels; theme toggles expose
aria-pressed; counters get accessible names.

Recorded in openspec change material-icons-ui (all tasks complete).
2026-10-10 13:19:29 +03:00
iu 2b2b342492 feat: implement shared-album multi-user photo album
Backend (Go/Gin/pgx): env config, pgx pool with retries, Garage S3 client
(path-style, region garage), embedded golang-migrate migrations, JWT auth with
refresh rotation, albums CRUD, members/roles/invites with no-escalation matrix,
photo upload + async imaging/goexif WebP variants, cursor pagination, presigned
URLs, likes/comments, SSE hub (album + personal), notifications, share links.

Frontend (SvelteKit 2 + Svelte 5 + Tailwind v4): API wrapper with 401 refresh,
auth store, all screens, Uploader/PhotoGrid/Lightbox/Comments, SSE client with
reconnect + REST catch-up, three themes + system via data-theme.

Deploy without Docker: Makefile builds the frontend into backend/static and
embeds it (go:embed) into a single statically linked binary; systemd unit and
nginx SSE example included.

Use gen2brain/webp (-tags nodynamic) instead of cgo kolesa-team/go-webp to keep
CGO_ENABLED=0 static builds; design.md/proposal.md updated accordingly.
2026-10-10 12:50:33 +03:00