refactor: remove table view from watchlist, keep only grid

This commit is contained in:
2026-04-21 01:41:11 +02:00
parent ebbc0c26f8
commit 4b29509127
4 changed files with 46 additions and 121 deletions

View File

@@ -211,11 +211,6 @@ func (h *Handler) HandleGetWatchlist(w http.ResponseWriter, r *http.Request) {
return return
} }
layout := r.URL.Query().Get("view")
if layout != "grid" && layout != "table" {
layout = "grid"
}
statusFilter := r.URL.Query().Get("status") statusFilter := r.URL.Query().Get("status")
sortBy := r.URL.Query().Get("sort") sortBy := r.URL.Query().Get("sort")
sortOrder := r.URL.Query().Get("order") sortOrder := r.URL.Query().Get("order")
@@ -255,7 +250,7 @@ func (h *Handler) HandleGetWatchlist(w http.ResponseWriter, r *http.Request) {
// Sort entries // Sort entries
h.sortEntries(filteredEntries, sortBy, sortOrder) h.sortEntries(filteredEntries, sortBy, sortOrder)
if err := templates.Watchlist(filteredEntries, layout, statusFilter, sortBy, sortOrder).Render(r.Context(), w); err != nil { if err := templates.Watchlist(filteredEntries, statusFilter, sortBy, sortOrder).Render(r.Context(), w); err != nil {
log.Printf("render error: %v", err) log.Printf("render error: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError) http.Error(w, "Internal Server Error", http.StatusInternalServerError)
} }

View File

@@ -3,7 +3,6 @@ package ui
type SortFilterOptions struct { type SortFilterOptions struct {
Sort string // "title", "date" Sort string // "title", "date"
Order string // "asc", "desc" Order string // "asc", "desc"
View string // for watchlist: "grid", "table"
Status string // for watchlist: "all", "watching", etc Status string // for watchlist: "all", "watching", etc
} }
@@ -27,9 +26,6 @@ templ SortFilter(opts SortFilterOptions) {
<form id="sort-form" method="get" class="hidden"> <form id="sort-form" method="get" class="hidden">
<input type="hidden" name="sort" id="sort-input" value={ opts.Sort }/> <input type="hidden" name="sort" id="sort-input" value={ opts.Sort }/>
<input type="hidden" name="order" id="order-input" value={ opts.Order }/> <input type="hidden" name="order" id="order-input" value={ opts.Order }/>
if opts.View != "" {
<input type="hidden" name="view" value={ opts.View }/>
}
if opts.Status != "" { if opts.Status != "" {
<input type="hidden" name="status" value={ opts.Status }/> <input type="hidden" name="status" value={ opts.Status }/>
} }

View File

@@ -33,8 +33,8 @@ func FormatEstablishedDate(date string) string {
} }
// WatchlistURL builds the watchlist URL with query parameters // WatchlistURL builds the watchlist URL with query parameters
func WatchlistURL(view string, status string, sortBy string, sortOrder string) string { func WatchlistURL(status string, sortBy string, sortOrder string) string {
return fmt.Sprintf("/watchlist?view=%s&status=%s&sort=%s&order=%s", view, status, sortBy, sortOrder) return fmt.Sprintf("/watchlist?status=%s&sort=%s&order=%s", status, sortBy, sortOrder)
} }
// AnimeURL builds the anime detail URL // AnimeURL builds the anime detail URL

View File

@@ -12,7 +12,6 @@ import (
templ Watchlist( templ Watchlist(
entries []db.GetUserWatchListRow, entries []db.GetUserWatchListRow,
viewLayout string,
currentStatus string, currentStatus string,
sortBy string, sortBy string,
sortOrder string, sortOrder string,
@@ -57,59 +56,44 @@ templ Watchlist(
onchange="htmx.trigger('#import-form', 'submit')" onchange="htmx.trigger('#import-form', 'submit')"
/> />
</form> </form>
<div
class="flex flex-wrap gap-2 max-md:flex-nowrap max-md:overflow-x-auto max-md:pb-1"
>
<a
href={ templ.URL(shared.WatchlistURL(viewLayout, "all", sortBy, sortOrder)) }
class={ shared.TabClass(viewLayout == "grid") }
>
Grid
</a>
<a
href={ templ.URL(shared.WatchlistURL(viewLayout, "table", sortBy, sortOrder)) }
class={ shared.TabClass(viewLayout == "table") }
>
Table
</a>
</div>
</div> </div>
</div> </div>
<div <div
class="mb-3 flex flex-wrap gap-2 max-md:flex-nowrap max-md:overflow-x-auto max-md:pb-1" class="mb-3 flex flex-wrap gap-2 max-md:flex-nowrap max-md:overflow-x-auto max-md:pb-1"
> >
<a <a
href={ templ.URL(shared.WatchlistURL(viewLayout, "all", sortBy, sortOrder)) } href={ templ.URL(shared.WatchlistURL("all", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "all") } class={ shared.TabClass(currentStatus == "all") }
> >
All All
</a> </a>
<a <a
href={ templ.URL(shared.WatchlistURL(viewLayout, "watching", sortBy, sortOrder)) } href={ templ.URL(shared.WatchlistURL("watching", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "watching") } class={ shared.TabClass(currentStatus == "watching") }
> >
Watching Watching
</a> </a>
<a <a
href={ templ.URL(shared.WatchlistURL(viewLayout, "on_hold", sortBy, sortOrder)) } href={ templ.URL(shared.WatchlistURL("on_hold", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "on_hold") } class={ shared.TabClass(currentStatus == "on_hold") }
> >
On hold On hold
</a> </a>
<a <a
href={ templ.URL(shared.WatchlistURL(viewLayout, "plan_to_watch", sortBy, sortOrder)) } href={ templ.URL(shared.WatchlistURL("plan_to_watch", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "plan_to_watch") } class={ shared.TabClass(currentStatus == "plan_to_watch") }
> >
Plan to watch Plan to watch
</a> </a>
<a <a
href={ templ.URL(shared.WatchlistURL(viewLayout, "dropped", sortBy, sortOrder)) } href={ templ.URL(shared.WatchlistURL("dropped", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "dropped") } class={ shared.TabClass(currentStatus == "dropped") }
> >
Dropped Dropped
</a> </a>
<a <a
href={ templ.URL(shared.WatchlistURL(viewLayout, "completed", sortBy, sortOrder)) } href={ templ.URL(shared.WatchlistURL("completed", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "completed") } class={ shared.TabClass(currentStatus == "completed") }
> >
Completed Completed
@@ -118,7 +102,6 @@ templ Watchlist(
@components.SortFilter(components.SortFilterOptions{ @components.SortFilter(components.SortFilterOptions{
Sort: sortBy, Sort: sortBy,
Order: sortOrder, Order: sortOrder,
View: viewLayout,
Status: currentStatus, Status: currentStatus,
}) })
if len(entries) == 0 { if len(entries) == 0 {
@@ -130,92 +113,43 @@ templ Watchlist(
} }
} }
} else { } else {
if viewLayout == "grid" { <div
<div class="grid grid-cols-2 gap-3 sm:grid-cols-3 md:gap-4 lg:grid-cols-4 xl:grid-cols-5"
class="grid grid-cols-2 gap-3 sm:grid-cols-3 md:gap-4 lg:grid-cols-4 xl:grid-cols-5" >
> for _, entry := range entries {
for _, entry := range entries { <div
<div class="group relative min-w-0"
class="group relative min-w-0" id={ fmt.Sprintf("watchlist-entry-%d", entry.AnimeID) }
id={ fmt.Sprintf("watchlist-entry-%d", entry.AnimeID) } >
<a
href={ templ.URL(shared.AnimeURL(int(entry.AnimeID))) }
class="flex flex-col bg-transparent text-inherit no-underline"
> >
<a <div class="relative flex w-full aspect-2/3 justify-center overflow-hidden">
href={ templ.URL(shared.AnimeURL(int(entry.AnimeID))) } <img
class="flex flex-col bg-transparent text-inherit no-underline" src={ entry.ImageUrl }
> alt={ entry.DisplayTitle() }
<div class="relative flex w-full aspect-2/3 justify-center overflow-hidden"> class="block w-full object-cover object-center"
<img loading="lazy"
src={ entry.ImageUrl } />
alt={ entry.DisplayTitle() } <div class="absolute inset-0 bg-black/0 transition-colors duration-200 group-hover:bg-black/40"></div>
class="block w-full object-cover object-center" </div>
loading="lazy" <div class="mt-2 line-clamp-2 text-sm leading-snug text-(--text)">
/> { entry.DisplayTitle() }
<div class="absolute inset-0 bg-black/0 transition-colors duration-200 group-hover:bg-black/40"></div> </div>
</div> @watchlist.Progress(entry)
<div class="mt-2 line-clamp-2 text-sm leading-snug text-(--text)"> </a>
{ entry.DisplayTitle() } <button
</div> class="absolute right-2 top-2 h-6 w-6 cursor-pointer border-0 bg-(--overlay-subtle) text-(--text-muted) opacity-0 transition-opacity duration-150 group-hover:opacity-100 hover:text-(--danger)"
@watchlist.Progress(entry) hx-delete={ string(templ.URL(fmt.Sprintf("/api/watchlist/%d?from=watchlist", entry.AnimeID))) }
</a> hx-target={ fmt.Sprintf("#watchlist-entry-%d", entry.AnimeID) }
<button hx-swap="delete"
class="absolute right-2 top-2 h-6 w-6 cursor-pointer border-0 bg-(--overlay-subtle) text-(--text-muted) opacity-0 transition-opacity duration-150 group-hover:opacity-100 hover:text-(--danger)" >
hx-delete={ string(templ.URL(fmt.Sprintf("/api/watchlist/%d?from=watchlist", entry.AnimeID))) } &times;
hx-target={ fmt.Sprintf("#watchlist-entry-%d", entry.AnimeID) } </button>
hx-swap="delete" </div>
> }
&times; </div>
</button>
</div>
}
</div>
} else {
<table
class="block w-full overflow-x-auto whitespace-nowrap bg-(--panel) md:table md:overflow-visible md:whitespace-normal"
>
<thead>
<tr>
<th class="p-2.5"></th>
<th class="p-2.5 text-left text-xs text-(--text-faint)">Title</th>
<th class="p-2.5"></th>
</tr>
</thead>
<tbody>
for _, entry := range entries {
<tr
class="hover:bg-(--panel-soft)"
id={ fmt.Sprintf("watchlist-entry-%d", entry.AnimeID) }
>
<td class="p-2.5">
<a href={ templ.URL(shared.AnimeURL(int(entry.AnimeID))) }>
<img
src={ entry.ImageUrl }
alt={ entry.DisplayTitle() }
class="aspect-2/3 w-9 object-cover"
loading="lazy"
/>
</a>
</td>
<td class="p-2.5 font-medium">
<a href={ templ.URL(shared.AnimeURL(int(entry.AnimeID))) }>
{ entry.DisplayTitle() }
</a>
@watchlist.Progress(entry)
</td>
<td class="w-24 p-2.5">
<button
class="cursor-pointer border-0 bg-transparent p-0 text-xs text-(--text-muted) hover:text-(--danger)"
hx-delete={ string(templ.URL(fmt.Sprintf("/api/watchlist/%d?from=watchlist", entry.AnimeID))) }
hx-target={ fmt.Sprintf("#watchlist-entry-%d", entry.AnimeID) }
hx-swap="delete"
>
Remove
</button>
</td>
</tr>
}
</tbody>
</table>
}
} }
} }
} }