Files

7.0 KiB
Raw Permalink Blame History

Tasks

1. PhotoGrid: API курсора и визуализация

  • 1.1 Добавить в lib/components/PhotoGrid.svelte проп cursorIndex и колбэки onCursor, onToggle, onExtend, onOpen, onClear; прокинуть их из routes/(app)/albums/[id]/+page.svelte. Проверка: cd frontend && npm run check проходит, сетка рендерится без изменений поведения мыши.
  • 1.2 Реализовать roving tabindex: у ячейки под курсором tabindex="0", у остальных -1; при пустом курсоре 0 у первой ячейки. Проверка: Tab вводит фокус в сетку один раз, стрелки не покидают сетку.
  • 1.3 Добавить визуальный контур курсора (data-cursor, внешний outline-2 outline-offset-2 в токене text) с показом только при :focus-within. Проверка: в светлой, тёмной и нейтральной темах контур отличим от ring-primary и читается, когда ячейка одновременно выделена и под курсором.

2. Клавиши сетки

  • 2.1 Реализовать геометрию перемещения по плоскому индексу: ←/→ — index ± 1 (естественный переход на соседнюю строку), ↑/↓ — index ± density.cols с зажимом в [0, n-1]. Проверка: ручной прогон — → в конце строки уходит на следующую строку, ↑/↓ не переносят через верх/низ.
  • 2.2 Повесить keydown на контейнер сетки (не на window); игнорировать события вне фокуса сетки; preventDefault только для обрабатываемых клавиш. Проверка: при фокусе в поле ввода панели или в диалоге стрелки и Space не двигают курсор.
  • 2.3 Обработать клавиши-действия: Space → onToggle, Shift+стрелка → onExtend, Enter → onOpen, Esc → onClear. Проверка: Space переключает выделение и обновляет правую панель, Shift+стрелка расширяет диапазон от якоря, Enter открывает просмотр, Esc снимает выделение и оставляет курсор.

3. Снятие выделения кликом

  • 3.1 Добавить обработчик клика на контейнер сетки вместе с отступами: пропускать цель внутри [data-photo-cell], иначе selection.clear(); контейнеру дать tabindex="-1" и фокусировать его после снятия. Проверка: клик по пустому месту возвращает в правой панели свойства альбома, клик по фото/кнопке тулбара/элементу панели выделение не снимает, после снятия стрелки сразу двигают курсор.

4. Интеграция страницы альбома

  • 4.1 Ввести cursorIndex в +page.svelte; синхронизировать с мышью (клик, ctrl/cmd-клик, shift-клик, контекстное меню ставят курсор); сбрасывать в null при смене альбома в том же $effect, где selection.clear().
  • 4.2 При перемещении курсора вызывать scrollIntoView({ block: 'nearest' }) для ячейки. Проверка: движение к краю прокручивает сетку, ячейка под курсором видна.
  • 4.3 При движении вперёд за последнее загруженное фото и наличии nextCursor вызывать loadMore(), затем ставить курсор на новое фото; без nextCursor — зажим. Проверка: → на последнем загруженном фото догружает следующую порцию и перемещает курсор.
  • 4.4 Реализовать onExtend: если якорь не задан, взять текущий курсор; выставлять выделение диапазоном от якоря до курсора через selection.set. Проверка: Shift+стрелка добавляет соседние фото в выделение, правая панель показывает количество.

5. Интеграционная проверка

  • 5.1 Прогнать cd frontend && npm run check без ошибок типов и предупреждений.
  • 5.2 Вручную пройти сценарии дельты ui-workspace в светлой, тёмной и нейтральной темах: движение курсора без смены панели, Space+панель, Shift-диапазон, Enter, Esc, клик по пустому месту, догрузка; убедиться, что клик/дабл-клик/контекстное меню/drag работают как прежде.

6. Возврат фокуса из просмотра

  • 6.1 Добавить модульный стор lib/stores/viewer-return.ts (однослотовая память {albumId, photoId} с remember/consume) и вызывать remember(albumId, photoId) в routes/(app)/albums/[id]/photos/[photoId]/+page.svelte через $effect на photoId. Проверка: npm run check проходит; при открытии просмотра и листании слот хранит текущий photoId.
  • 6.2 В routes/(app)/albums/[id]/+page.svelte в $effect на albumId вызывать viewerReturn.consume(albumId), а после loading = false и tick() — восстанавливать фокус: selection.set(albumId, [photo]), anchorId, cursorIndex, .focus({preventScroll:true}) и scrollIntoView({block:'center'}); если фото нет среди загруженных — догружать loadMore() в цикле. Проверка: возврат из просмотра выделяет и фокусирует просмотренное фото, стрелки работают сразу; фото со второй страницы догружается.
  • 6.3 Расширить QA-скрипт сценариями возврата (закрытие просмотра, листание и возврат, фото вне первой страницы, возврат в другой альбом) и прогнать его. Проверка: все проверки PASS, npm run check без ошибок и предупреждений.