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
}
layout := r.URL.Query().Get("view")
if layout != "grid" && layout != "table" {
layout = "grid"
}
statusFilter := r.URL.Query().Get("status")
sortBy := r.URL.Query().Get("sort")
sortOrder := r.URL.Query().Get("order")
@@ -255,7 +250,7 @@ func (h *Handler) HandleGetWatchlist(w http.ResponseWriter, r *http.Request) {
// Sort entries
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)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}

View File

@@ -3,7 +3,6 @@ package ui
type SortFilterOptions struct {
Sort string // "title", "date"
Order string // "asc", "desc"
View string // for watchlist: "grid", "table"
Status string // for watchlist: "all", "watching", etc
}
@@ -27,9 +26,6 @@ templ SortFilter(opts SortFilterOptions) {
<form id="sort-form" method="get" class="hidden">
<input type="hidden" name="sort" id="sort-input" value={ opts.Sort }/>
<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 != "" {
<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
func WatchlistURL(view string, status string, sortBy string, sortOrder string) string {
return fmt.Sprintf("/watchlist?view=%s&status=%s&sort=%s&order=%s", view, status, sortBy, sortOrder)
func WatchlistURL(status string, sortBy string, sortOrder string) string {
return fmt.Sprintf("/watchlist?status=%s&sort=%s&order=%s", status, sortBy, sortOrder)
}
// AnimeURL builds the anime detail URL

View File

@@ -12,7 +12,6 @@ import (
templ Watchlist(
entries []db.GetUserWatchListRow,
viewLayout string,
currentStatus string,
sortBy string,
sortOrder string,
@@ -57,59 +56,44 @@ templ Watchlist(
onchange="htmx.trigger('#import-form', 'submit')"
/>
</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
class="mb-3 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)) }
href={ templ.URL(shared.WatchlistURL("all", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "all") }
>
All
</a>
<a
href={ templ.URL(shared.WatchlistURL(viewLayout, "watching", sortBy, sortOrder)) }
href={ templ.URL(shared.WatchlistURL("watching", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "watching") }
>
Watching
</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") }
>
On hold
</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") }
>
Plan to watch
</a>
<a
href={ templ.URL(shared.WatchlistURL(viewLayout, "dropped", sortBy, sortOrder)) }
href={ templ.URL(shared.WatchlistURL("dropped", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "dropped") }
>
Dropped
</a>
<a
href={ templ.URL(shared.WatchlistURL(viewLayout, "completed", sortBy, sortOrder)) }
href={ templ.URL(shared.WatchlistURL("completed", sortBy, sortOrder)) }
class={ shared.TabClass(currentStatus == "completed") }
>
Completed
@@ -118,7 +102,6 @@ templ Watchlist(
@components.SortFilter(components.SortFilterOptions{
Sort: sortBy,
Order: sortOrder,
View: viewLayout,
Status: currentStatus,
})
if len(entries) == 0 {
@@ -130,92 +113,43 @@ templ Watchlist(
}
}
} else {
if viewLayout == "grid" {
<div
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 {
<div
class="group relative min-w-0"
id={ fmt.Sprintf("watchlist-entry-%d", entry.AnimeID) }
<div
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 {
<div
class="group relative min-w-0"
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
href={ templ.URL(shared.AnimeURL(int(entry.AnimeID))) }
class="flex flex-col bg-transparent text-inherit no-underline"
>
<div class="relative flex w-full aspect-2/3 justify-center overflow-hidden">
<img
src={ entry.ImageUrl }
alt={ entry.DisplayTitle() }
class="block w-full object-cover object-center"
loading="lazy"
/>
<div class="absolute inset-0 bg-black/0 transition-colors duration-200 group-hover:bg-black/40"></div>
</div>
<div class="mt-2 line-clamp-2 text-sm leading-snug text-(--text)">
{ entry.DisplayTitle() }
</div>
@watchlist.Progress(entry)
</a>
<button
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))) }
hx-target={ fmt.Sprintf("#watchlist-entry-%d", entry.AnimeID) }
hx-swap="delete"
>
&times;
</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>
}
<div class="relative flex w-full aspect-2/3 justify-center overflow-hidden">
<img
src={ entry.ImageUrl }
alt={ entry.DisplayTitle() }
class="block w-full object-cover object-center"
loading="lazy"
/>
<div class="absolute inset-0 bg-black/0 transition-colors duration-200 group-hover:bg-black/40"></div>
</div>
<div class="mt-2 line-clamp-2 text-sm leading-snug text-(--text)">
{ entry.DisplayTitle() }
</div>
@watchlist.Progress(entry)
</a>
<button
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))) }
hx-target={ fmt.Sprintf("#watchlist-entry-%d", entry.AnimeID) }
hx-swap="delete"
>
&times;
</button>
</div>
}
</div>
}
}
}