refactor: remove table view from watchlist, keep only grid
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 }/>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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))) }
|
×
|
||||||
hx-target={ fmt.Sprintf("#watchlist-entry-%d", entry.AnimeID) }
|
</button>
|
||||||
hx-swap="delete"
|
</div>
|
||||||
>
|
}
|
||||||
×
|
</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>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user