diff --git a/api/anime/handler.go b/api/anime/handler.go index 1c934f5..6dbc608 100644 --- a/api/anime/handler.go +++ b/api/anime/handler.go @@ -182,6 +182,7 @@ func (h *Handler) HandleAnimeDetails(w http.ResponseWriter, r *http.Request) { user, _ := r.Context().Value(ctxpkg.UserKey).(*database.User) var status string + var watchlistIDs []int64 if user != nil { entry, err := h.db.GetWatchListEntry(r.Context(), database.GetWatchListEntryParams{ UserID: user.ID, @@ -190,13 +191,19 @@ func (h *Handler) HandleAnimeDetails(w http.ResponseWriter, r *http.Request) { if err == nil { status = entry.Status } + watchlist, _ := h.db.GetUserWatchList(r.Context(), user.ID) + watchlistIDs = make([]int64, len(watchlist)) + for i, e := range watchlist { + watchlistIDs[i] = e.AnimeID + } } if err := templates.GetRenderer().ExecuteTemplate(w, "anime.gohtml", map[string]any{ - "Anime": anime, - "User": user, - "Status": status, - "CurrentPath": r.URL.Path, + "Anime": anime, + "User": user, + "Status": status, + "CurrentPath": r.URL.Path, + "WatchlistIDs": watchlistIDs, }); err != nil { log.Printf("render error: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) @@ -218,9 +225,19 @@ func (h *Handler) HandleHTMLWatchOrder(w http.ResponseWriter, r *http.Request) { return } + user, _ := r.Context().Value(ctxpkg.UserKey).(*database.User) + watchlistMap := make(map[int64]bool) + if user != nil { + watchlist, _ := h.db.GetUserWatchList(r.Context(), user.ID) + for _, entry := range watchlist { + watchlistMap[entry.AnimeID] = true + } + } + if err := templates.GetRenderer().ExecuteFragment(w, "anime.gohtml", "watch_order", map[string]any{ - "Relations": relations, - "AnimeID": id, + "Relations": relations, + "AnimeID": id, + "WatchlistMap": watchlistMap, }); err != nil { log.Printf("render error: %v", err) } diff --git a/templates/anime.gohtml b/templates/anime.gohtml index e0b02a4..bacaa88 100644 --- a/templates/anime.gohtml +++ b/templates/anime.gohtml @@ -1,5 +1,6 @@ {{define "title"}}{{.Anime.DisplayTitle}}{{end}} {{define "content"}} +{{if .WatchlistIDs}}{{end}} {{$anime := .Anime}}
diff --git a/templates/base.gohtml b/templates/base.gohtml index 2ec5362..2e1bb0c 100644 --- a/templates/base.gohtml +++ b/templates/base.gohtml @@ -48,15 +48,47 @@ watchlistIds.delete(id) btn.classList.remove('in-watchlist') btn.setAttribute('aria-label', 'Add to Watchlist') + + // Update dropdown status if on anime page + syncWatchlistDropdown(id, false) } else { watchlistIds.add(id) btn.classList.add('in-watchlist') btn.setAttribute('aria-label', 'Remove from Watchlist') + + // Update dropdown status if on anime page + syncWatchlistDropdown(id, true) } + + // Update all other watchlist icons on the page for this anime + document.querySelectorAll('.watchlist-icon').forEach(function(icon) { + const button = icon.closest('button') + if (button && button !== btn) { + const malId = button.dataset.malId + if (malId && parseInt(malId) === id) { + if (watchlistIds.has(id)) { + button.classList.add('in-watchlist') + } else { + button.classList.remove('in-watchlist') + } + } + } + }) } }) } + function syncWatchlistDropdown(id, inWatchlist) { + const statusDisplay = document.getElementById('watchlist-status-display-' + id) + if (statusDisplay) { + statusDisplay.textContent = inWatchlist ? 'Plan to Watch' : 'Add to Watchlist' + const removeContainer = document.getElementById('remove-watchlist-container-' + id) + if (removeContainer) { + removeContainer.classList.toggle('hidden', !inWatchlist) + } + } + } + function removeFromWatchlist(id, btn) { fetch(`/api/watchlist/${id}`, { method: 'DELETE' }).then(res => { if (res.ok) { diff --git a/templates/components/anime_card.gohtml b/templates/components/anime_card.gohtml index df35902..9e3808e 100644 --- a/templates/components/anime_card.gohtml +++ b/templates/components/anime_card.gohtml @@ -37,7 +37,7 @@ {{end}}
-
diff --git a/templates/components/watch_order.gohtml b/templates/components/watch_order.gohtml index 7cb8a2a..7ea774e 100644 --- a/templates/components/watch_order.gohtml +++ b/templates/components/watch_order.gohtml @@ -4,7 +4,7 @@
{{range .Relations}}
- {{template "anime_card" dict "Anime" .Anime "WithActions" true "Compact" true "HasTopBadge" true}} + {{template "anime_card" dict "Anime" .Anime "WithActions" true "Compact" true "HasTopBadge" true "IsWatchlist" (index $.WatchlistMap .Anime.MalID)}} {{if eq .Anime.MalID $.AnimeID}}
CURRENT diff --git a/templates/components/watchlist_actions.gohtml b/templates/components/watchlist_actions.gohtml index 882fd2a..ab272e5 100644 --- a/templates/components/watchlist_actions.gohtml +++ b/templates/components/watchlist_actions.gohtml @@ -11,7 +11,7 @@ {{if $status}} {{if eq $status "watching"}}Watching{{end}} {{if eq $status "completed"}}Completed{{end}} - {{if eq $status "plan to watch"}}Plan to Watch{{end}} + {{if eq $status "plan_to_watch"}}Plan to Watch{{end}} {{if eq $status "dropped"}}Dropped{{end}} {{else}} Add to Watchlist @@ -63,6 +63,17 @@ document.getElementById('watchlist-status-display-' + id).textContent = display; document.getElementById('remove-watchlist-container-' + id).classList.remove('hidden'); + // Update all watchlist icons on the page + document.querySelectorAll('.watchlist-icon').forEach(function(icon) { + const button = icon.closest('button') + if (button) { + const malId = button.dataset.malId + if (malId && parseInt(malId) === id) { + button.classList.add('in-watchlist') + } + } + }); + // Close dropdown after a small delay to let click event finish requestAnimationFrame(() => { const dropdown = btn.closest('ui-dropdown'); @@ -79,6 +90,17 @@ document.getElementById('watchlist-status-display-' + id).textContent = 'Add to Watchlist'; document.getElementById('remove-watchlist-container-' + id).classList.add('hidden'); + // Update all watchlist icons on the page + document.querySelectorAll('.watchlist-icon').forEach(function(icon) { + const button = icon.closest('button') + if (button) { + const malId = button.dataset.malId + if (malId && parseInt(malId) === id) { + button.classList.remove('in-watchlist') + } + } + }); + // Close dropdown const btn = document.getElementById('watchlist-status-display-' + id); if (btn) {