Returning to the grid at a deep position (deep link / hard reload to a
file, then back → /files?anchor=<id>) used to load only a tiny forward
window at the anchor. Now the grid fills the viewport around the anchor
and pages in both directions as the user scrolls.
- loadAroundAnchor fetches a window centred on the anchor and pre-fills a
few pages each way sequentially, then centres on the anchor once. Doing
the initial fill explicitly (rather than via the sentinels) keeps the
pages contiguous and leaves the sentinels out of range, so there's no
mount-time load storm.
- loading starts true when the URL carries an ?anchor, so the child
InfiniteScroll sentinels (whose effects run before this page's reset
effect on mount) can't fire a stray page-1 loadMore that interleaves
with loadAroundAnchor.
- loadPrev pages backward (direction=backward) and prepends, then shifts
the scroller down by the added height via flushSync (no paint between
prepend and correction) so the viewport stays visually fixed.
- InfiniteScroll gains an `edge` prop; a top instance (shown only when
hasPrev) drives upward loading. Both loaders share the `loading` guard.
- Mock: honour direction=backward and emit prev_cursor; the Go backend
already supports backward keyset pagination.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
75 mock files fit in a single 100-item page, so infinite scroll never
fired. 500 yields 5 cursor pages for testing lazy loading and the
overlay viewer paging past the loaded set.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- vite-mock-plugin: define the missing MockFile type and annotate the
MOCK_FILES / MOCK_TRASH arrays so restore (unshift) type-checks.
- categories/[id], tags/[id]: page.params.id is string | undefined under
noUncheckedIndexedAccess — guard loadTags and default the TagRuleEditor
tagId so the routes type-check.
svelte-check now reports 0 errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New /files/trash page: same grid as files view, deleted files only
- Tap selects (no detail page for deleted files), long-press drag-selects
- Trash selection bar: Restore (bulk) and Delete permanently (bulk, confirmed)
- Trash icon added to files header, navigates to /files/trash
- Mock: MOCK_TRASH with 6 pre-seeded files; bulk/delete now moves to trash;
handlers for POST /files/{id}/restore and DELETE /files/{id}/permanent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Layout guard redirecting non-admins to /files
- User list page with create form and delete confirmation
- User detail page with role/permission toggles and delete
- Audit log page with filters (user, action, object type, ID, date range)
- Mock data: 5 test users, 80 audit entries, full CRUD handlers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Profile editor: name and optional password change with confirm field,
saves via PATCH /users/me and updates auth store
- Appearance: theme toggle button (dark/light) with sun/moon icon
- App cache: PWA reset — unregisters service workers and clears caches
- Sessions: list active sessions with parsed user agent, start date,
expiry, current badge, and terminate button per session
- Add mock handlers: PATCH /users/me, DELETE /auth/sessions/{id}
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add BulkTagEditor component: loads common/partial tags via
POST /files/bulk/common-tags and applies changes via POST /files/bulk/tags
- Common tags shown solid with × to remove from all files
- Partial tags shown with dashed border and ~ indicator; clicking promotes
to common (adds to files that are missing it)
- Wire "Edit tags" button in SelectionBar to a bottom sheet with the editor
- Add mock handlers for /files/bulk/common-tags and /files/bulk/tags
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add /pools list page with search, sort, load-more pagination
- Add /pools/new create form (name, notes, public toggle)
- Add /pools/[id] detail page: metadata editing, ordered file grid,
drag-to-reorder, filter bar, file selection/removal, add-files overlay
- Add pool sort store (poolSorting) to sorting.ts
- Wire "Add to pool" button in SelectionBar: bottom-sheet pool picker
loads pool list, user picks one, selected files are POSTed to pool
- Add full pool mock API handlers in vite-mock-plugin.ts (CRUD + file
management: add, remove, reorder with cursor pagination)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- /categories: list with colored pills, search + clear, sort/order controls
- /categories/new: create form with name, color picker, notes, is_public
- /categories/[id]: edit form + tags-in-category section with load more
- sorting.ts: add categorySorting store (name/color/created, persisted)
- mock: category CRUD, GET /categories/{id}/tags, search/sort/offset
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Toggle button (filled/hollow circle) on each rule row
- Inactive rules dim to 45% opacity
- Toggle via delete + recreate with new is_active value
- Mock: track is_active per rule (Map instead of Set)
- Show all available tags by default in add-rule picker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a Vite dev-only middleware that intercepts /api/v1/* requests
and returns mock responses for auth, users, files, tags, categories,
and pools. Login with any username and password "password".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>