From 625e256944c6fd30ac8d3f9c7051a67e801e0b26 Mon Sep 17 00:00:00 2001 From: Garret Patti <42485635+garretpatti@users.noreply.github.com> Date: Sat, 18 Apr 2026 11:10:26 -0400 Subject: [PATCH] reduce repeated tag selector code --- src/components/games/GameDetailModal.tsx | 51 +- src/components/mixed/ImageLightbox.tsx | 541 +++++++++------------ src/components/mixed/VideoPlayerModal.tsx | 94 +--- src/components/movies/MovieDetailModal.tsx | 51 +- src/components/tags/MediaTagPanel.tsx | 135 +++++ src/components/tv/TvView.tsx | 90 ++-- 6 files changed, 418 insertions(+), 544 deletions(-) create mode 100644 src/components/tags/MediaTagPanel.tsx diff --git a/src/components/games/GameDetailModal.tsx b/src/components/games/GameDetailModal.tsx index 0dbafd7..5221876 100644 --- a/src/components/games/GameDetailModal.tsx +++ b/src/components/games/GameDetailModal.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef, useState, useCallback } from 'react' import type { Game, GameFile, GamePlatform } from '@/types' -import TagSelector from '@/components/tags/TagSelector' +import MediaTagPanel from '@/components/tags/MediaTagPanel' import AssignedTagBadges from '@/components/tags/AssignedTagBadges' // Import SVG icons @@ -525,49 +525,12 @@ export default function GameDetailModal({ game, libraryId, onClose, onPrev, onNe {/* ── Tag panel — bottom half on mobile, right sidebar on desktop ── */} {showTagPanel && ( -
e.stopPropagation()} - > - {/* Panel header — ‹ hide | ✕ close */} -
- - -
- - {/* Tags */} -
-

- Tags -

- { setTagRefreshKey((k) => k + 1); onTagsChanged?.() }} - refreshKey={tagRefreshKey} - /> -
-
+ setShowTagPanel(false)} + onClose={onClose} + onTagsChanged={() => { setTagRefreshKey((k) => k + 1); onTagsChanged?.() }} + /> )} diff --git a/src/components/mixed/ImageLightbox.tsx b/src/components/mixed/ImageLightbox.tsx index 12316b2..5a1197a 100644 --- a/src/components/mixed/ImageLightbox.tsx +++ b/src/components/mixed/ImageLightbox.tsx @@ -1,7 +1,7 @@ 'use client' import { useEffect, useRef, useState, useCallback } from 'react' -import TagSelector from '@/components/tags/TagSelector' +import MediaTagPanel from '@/components/tags/MediaTagPanel' interface Props { url: string @@ -21,10 +21,6 @@ export default function ImageLightbox({ url, name, onClose, onPrev, onNext, item const [showTagsLocal, setShowTagsLocal] = useState(false) const showTags = showTagsProp ?? showTagsLocal const setShowTags = onShowTagsChange ?? setShowTagsLocal - const [aiTagging, setAiTagging] = useState(false) - const [aiTagError, setAiTagError] = useState(null) - const [tagRefreshKey, setTagRefreshKey] = useState(0) - // Text extraction state const [extractedText, setExtractedText] = useState(null) const [translatedText, setTranslatedText] = useState(null) @@ -211,22 +207,6 @@ export default function ImageLightbox({ url, name, onClose, onPrev, onNext, item } } - const handleAiTag = async () => { - if (!onAiTag) return - setAiTagging(true) - setAiTagError(null) - try { - await onAiTag() - setTagRefreshKey((k) => k + 1) - onTagsChanged?.() - } catch (err) { - setAiTagError(err instanceof Error ? err.message : 'AI tagging failed') - setTimeout(() => setAiTagError(null), 4000) - } finally { - setAiTagging(false) - } - } - const smallBtn = 'w-7 h-7 rounded-full flex items-center justify-center transition-colors flex-shrink-0' return ( @@ -369,343 +349,270 @@ export default function ImageLightbox({ url, name, onClose, onPrev, onNext, item {/* ── Tag panel — bottom half on mobile, right sidebar on desktop ── */} {showTags && ( -
e.stopPropagation()} + setShowTags(false)} + onClose={onClose} + onTagsChanged={onTagsChanged} + onAiTag={onAiTag} > - {/* Panel header — ‹ hide | ✨ AI tag ✕ close */} -
- -
+ {/* Description section */} +
+
+

+ Description +

+