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) {