- Party.svelte: Add 'Sync from collection' to overflow menu for parties
with linked collection items, with proper menu grouping
- SearchContent.svelte: Highlight items user owns in 'All Items' mode
with subtle green background and checkmark indicator
# feat: migrate components to TanStack Query v6 (Phase 2)
## Summary
This PR migrates 4 components from the custom
`createInfiniteScrollResource` pattern to TanStack Query v6's
`createInfiniteQuery`:
- **JobSkillSelectionSidebar** - Job skill search with infinite scroll
and category filtering
- **SearchContent** - Search modal for weapons/characters/summons with
element/rarity/proficiency filters
- **User Profile Page** (`[username]/+page.svelte`) - User's teams and
favorites with tab switching
- **Teams Explore Page** (`teams/explore/+page.svelte`) - Public teams
listing
All components now use:
- TanStack Query v6 infinite query pattern with thunk for reactivity
- `IsInViewport` from runed for intersection-based infinite scroll
- Debounced search (debounce the value, not the query)
- Proper loading, error, and empty states
- SSR integration with `initialData` pattern
## Updates since last revision
- **Fixed duplicate key error in SearchContent.svelte** - The API can
return the same item across multiple pages during infinite scroll (e.g.,
due to items being added/removed between page fetches). This caused
Svelte's keyed each block to throw `each_key_duplicate` errors. Fixed by
deduplicating results by `id` using a Map before rendering.
## Review & Testing Checklist for Human
This is a medium-risk change affecting core user-facing pages. Please
verify:
- [ ] **Infinite scroll works on all 4 pages** - Scroll to bottom and
verify more items load automatically
- [ ] **No duplicate items appear in search results** - After the fix,
scrolling through many pages of search results should not show
duplicates
- [ ] **SSR hydration** - Verify no flash of loading state on initial
page load (data should be pre-rendered)
- [ ] **User profile tab switching** - Test switching between "Teams"
and "Favorites" tabs; verify correct data loads
- [ ] **Search debouncing** - Type quickly in JobSkillSelectionSidebar
and SearchContent; verify queries aren't fired on every keystroke
- [ ] **Error states** - Simulate network failure and verify retry
button works
**Recommended Test Plan:**
1. Navigate to `/teams/explore` - verify teams load and infinite scroll
works
2. Navigate to a user profile page - verify teams load, switch to
favorites tab, verify favorites load
3. Open the search sidebar - search for weapons/characters/summons,
scroll through many pages, verify no duplicate key errors and no
duplicate items
4. Open job skill selection - search and filter skills, verify results
### Notes
- The Party component mutations migration (Follow-Up Prompt 5) was
deferred to a follow-up PR due to complexity
- Deprecated resource classes remain in codebase for now; removal
planned for separate PR
- Pre-existing paraglide module errors in build are unrelated to this PR
- Type assertions (`as unknown as`, `as any`) are used to handle
different query result structures between favorites and parties queries
**Link to Devin run:**
https://app.devin.ai/sessions/5aa7ea29edf34f569f95f13acee9e0d9
**Requested by:** Justin Edmund (justin@jedmund.com) / @jedmund
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Justin Edmund <justin@jedmund.com>
- DatabaseProvider.ts: Remove redundant normalizer check
- Normalizer is applied by parent class, no need to apply twice
- Fixes "Property 'normalizer' does not exist" error
- image.ts: Separate type and value exports for proper type resolution
- CharacterImageCell.svelte: Fix getCharacterImage parameter order
- Changed (id, pose, variant) to (id, variant, pose)
- SearchContent.svelte: Fix getCharacterImage parameter order
Fixes ImageVariant type errors and property access errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>