add library filter panel and tag selector enhancements

- Add left sidebar filter panel to MixedView and GamesView with name
  search and tag toggles; only shows tags/categories used in the current
  library; AND logic when multiple tags are selected
- Add GET /api/tags/library-assignments endpoint returning all tag
  assignments for a library keyed by mediaKey
- Add getTagAssignmentsForLibrary() and getTagsSortedByUsage() to tags lib
- Support ?sort=usage on GET /api/tags/items to order by assignment count
- Tag selector: per-category search, top-25-by-usage display, inline add
  tag (auto-assigned to current item) and add category flows
- Tag selector: group assigned tags by category into nested pills
- Fix nested <button> hydration error in EntryTile (outer element is now
  a div with role="button")
- Keep filter panel assignments in sync when tags are toggled or created

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-25 19:50:28 -04:00
parent 75fe82f0de
commit 43436f5cae
8 changed files with 643 additions and 122 deletions

View File

@@ -8,9 +8,10 @@ interface Props {
game: Game
libraryId: string
onClose: () => void
onTagsChanged?: () => void
}
export default function GameDetailModal({ game, libraryId, onClose }: Props) {
export default function GameDetailModal({ game, libraryId, onClose, onTagsChanged }: Props) {
const overlayRef = useRef<HTMLDivElement>(null)
useEffect(() => {
@@ -97,7 +98,7 @@ export default function GameDetailModal({ game, libraryId, onClose }: Props) {
<p className="text-xs font-semibold uppercase tracking-wider mb-2" style={{ color: 'var(--text-secondary)' }}>
Tags
</p>
<TagSelector mediaKey={`${libraryId}:${game.id}`} />
<TagSelector mediaKey={`${libraryId}:${game.id}`} onTagsChanged={onTagsChanged} />
</div>
</div>
</div>