ui: declutter anime pages and controls
This commit is contained in:
@@ -12,7 +12,7 @@ templ InfiniteAnimeList(animes []jikan.Anime, hasNext bool, nextURL string, cont
|
||||
</div>
|
||||
}
|
||||
if hasNext {
|
||||
<div class="scroll-trigger" style="grid-column: 1 / -1; height: 20px;" hx-get={ nextURL } hx-trigger="revealed" hx-swap="outerHTML"></div>
|
||||
<div class="scroll-trigger full-span-trigger" hx-get={ nextURL } hx-trigger="revealed" hx-swap="outerHTML"></div>
|
||||
}
|
||||
<script data-container={ containerID }>
|
||||
(function() {
|
||||
|
||||
@@ -24,8 +24,12 @@ templ SortFilter(opts SortFilterOptions) {
|
||||
<option value="asc" selected?={ opts.Order == "asc" }>Ascending</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="sort-filter-group density-group" aria-hidden="true">
|
||||
<span class="density-label">Density</span>
|
||||
<button type="button" class="density-toggle" id="density-toggle" onclick="document.body.classList.toggle('density-compact')">Compact</button>
|
||||
</div>
|
||||
</div>
|
||||
<form id="sort-form" method="get" style="display: none;">
|
||||
<form id="sort-form" method="get" class="is-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 != "" {
|
||||
|
||||
@@ -9,7 +9,7 @@ templ AnimeDetails(anime jikan.Anime, currentStatus string) {
|
||||
@Layout("mal - " + anime.DisplayTitle()) {
|
||||
<div class="anime-page">
|
||||
<div class="anime-main">
|
||||
<div class="anime-hero">
|
||||
<div class="anime-hero anime-surface">
|
||||
<div class="anime-poster">
|
||||
if anime.ImageURL() != "" {
|
||||
<img src={ anime.ImageURL() } alt={ anime.DisplayTitle() }/>
|
||||
@@ -41,7 +41,7 @@ templ AnimeDetails(anime jikan.Anime, currentStatus string) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="anime-synopsis">
|
||||
<section class="anime-synopsis anime-surface anime-section">
|
||||
<h3>Synopsis</h3>
|
||||
if anime.Synopsis != "" {
|
||||
<p>{ anime.Synopsis }</p>
|
||||
@@ -49,65 +49,56 @@ templ AnimeDetails(anime jikan.Anime, currentStatus string) {
|
||||
<p class="no-synopsis">No synopsis available.</p>
|
||||
}
|
||||
</section>
|
||||
<section class="anime-relations">
|
||||
<section class="anime-relations anime-surface anime-section">
|
||||
<h3>Related</h3>
|
||||
<div hx-get={ string(templ.URL(fmt.Sprintf("/api/anime/%d/relations", anime.MalID))) } hx-trigger="load">
|
||||
@ui.LoadingIndicator("Loading relations")
|
||||
</div>
|
||||
</section>
|
||||
<section class="anime-recommendations">
|
||||
<section class="anime-recommendations anime-surface anime-section">
|
||||
<h3>Recommendations</h3>
|
||||
<div hx-get={ string(templ.URL(fmt.Sprintf("/api/anime/%d/recommendations", anime.MalID))) } hx-trigger="load">
|
||||
@ui.LoadingIndicator("Loading recommendations")
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<aside class="anime-sidebar">
|
||||
if anime.TitleJapanese != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Japanese</span>
|
||||
<span class="sidebar-value">{ anime.TitleJapanese }</span>
|
||||
</div>
|
||||
}
|
||||
if len(anime.TitleSynonyms) > 0 {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Synonyms</span>
|
||||
<span class="sidebar-value">{ strings.Join(anime.TitleSynonyms, ", ") }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Aired.String != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Aired</span>
|
||||
<span class="sidebar-value">{ anime.Aired.String }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Premiered() != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Premiered</span>
|
||||
<span class="sidebar-value">{ anime.Premiered() }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Duration != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Duration</span>
|
||||
<span class="sidebar-value">{ anime.Duration }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Status != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Status</span>
|
||||
<span class="sidebar-value">{ anime.Status }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Score > 0 {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">MAL Score</span>
|
||||
<span class="sidebar-value">{ fmt.Sprintf("%.2f", anime.Score) }</span>
|
||||
</div>
|
||||
}
|
||||
<aside class="anime-sidebar anime-surface">
|
||||
<div class="anime-side-section">
|
||||
<h3>Details</h3>
|
||||
if anime.Aired.String != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Aired</span>
|
||||
<span class="sidebar-value">{ anime.Aired.String }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Premiered() != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Premiered</span>
|
||||
<span class="sidebar-value">{ anime.Premiered() }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Status != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Status</span>
|
||||
<span class="sidebar-value">{ anime.Status }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Score > 0 {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">MAL Score</span>
|
||||
<span class="sidebar-value">{ fmt.Sprintf("%.2f", anime.Score) }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Duration != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Duration</span>
|
||||
<span class="sidebar-value">{ anime.Duration }</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
if len(anime.Genres) > 0 {
|
||||
<div class="sidebar-row sidebar-row-wrap">
|
||||
<span class="sidebar-label">Genres</span>
|
||||
<div class="anime-side-section">
|
||||
<h3>Genres</h3>
|
||||
<div class="sidebar-tags">
|
||||
for _, g := range anime.Genres {
|
||||
<span class="sidebar-tag">{ g.Name }</span>
|
||||
@@ -115,25 +106,40 @@ templ AnimeDetails(anime jikan.Anime, currentStatus string) {
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
if len(anime.Studios) > 0 {
|
||||
if hasExtraSidebarDetails(anime) {
|
||||
<details class="anime-side-section side-details-more">
|
||||
<summary>More metadata</summary>
|
||||
if anime.TitleJapanese != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Japanese</span>
|
||||
<span class="sidebar-value">{ anime.TitleJapanese }</span>
|
||||
</div>
|
||||
}
|
||||
if len(anime.TitleSynonyms) > 0 {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Synonyms</span>
|
||||
<span class="sidebar-value">{ strings.Join(anime.TitleSynonyms, ", ") }</span>
|
||||
</div>
|
||||
}
|
||||
if len(anime.Studios) > 0 {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Studios</span>
|
||||
<span class="sidebar-value">{ joinNames(anime.Studios) }</span>
|
||||
</div>
|
||||
}
|
||||
if len(anime.Producers) > 0 {
|
||||
}
|
||||
if len(anime.Producers) > 0 {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Producers</span>
|
||||
<span class="sidebar-value">{ joinNames(anime.Producers) }</span>
|
||||
</div>
|
||||
}
|
||||
if anime.Source != "" {
|
||||
}
|
||||
if anime.Source != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Source</span>
|
||||
<span class="sidebar-value">{ anime.Source }</span>
|
||||
</div>
|
||||
}
|
||||
if len(anime.Demographics) > 0 {
|
||||
}
|
||||
if len(anime.Demographics) > 0 {
|
||||
<div class="sidebar-row sidebar-row-wrap">
|
||||
<span class="sidebar-label">Demographics</span>
|
||||
<div class="sidebar-tags">
|
||||
@@ -142,8 +148,8 @@ templ AnimeDetails(anime jikan.Anime, currentStatus string) {
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
if len(anime.Themes) > 0 {
|
||||
}
|
||||
if len(anime.Themes) > 0 {
|
||||
<div class="sidebar-row sidebar-row-wrap">
|
||||
<span class="sidebar-label">Themes</span>
|
||||
<div class="sidebar-tags">
|
||||
@@ -152,14 +158,14 @@ templ AnimeDetails(anime jikan.Anime, currentStatus string) {
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
if anime.Broadcast.String != "" {
|
||||
}
|
||||
if anime.Broadcast.String != "" {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Broadcast</span>
|
||||
<span class="sidebar-value">{ anime.Broadcast.String }</span>
|
||||
</div>
|
||||
}
|
||||
if len(anime.Streaming) > 0 {
|
||||
}
|
||||
if len(anime.Streaming) > 0 {
|
||||
<div class="sidebar-row">
|
||||
<span class="sidebar-label">Streaming</span>
|
||||
<div class="sidebar-value">
|
||||
@@ -168,20 +174,11 @@ templ AnimeDetails(anime jikan.Anime, currentStatus string) {
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</details>
|
||||
}
|
||||
</aside>
|
||||
</div>
|
||||
<script>
|
||||
function toggleDropdown() {
|
||||
document.getElementById('watchlist-dropdown').classList.toggle('open');
|
||||
}
|
||||
document.addEventListener('click', function(e) {
|
||||
const dropdown = document.getElementById('watchlist-dropdown');
|
||||
if (dropdown && !dropdown.contains(e.target)) {
|
||||
dropdown.classList.remove('open');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +282,7 @@ templ AnimeRelationsList(relations []jikan.RelationEntry) {
|
||||
}
|
||||
</div>
|
||||
} else {
|
||||
<p style="color: var(--text-muted); font-size: var(--text-sm);">No related anime found.</p>
|
||||
<p class="empty-inline-note">No related anime found.</p>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,6 +301,10 @@ templ AnimeRecommendations(recs []jikan.Anime) {
|
||||
}
|
||||
</div>
|
||||
} else {
|
||||
<p style="color: var(--text-muted); font-size: var(--text-sm);">No recommendations available.</p>
|
||||
<p class="empty-inline-note">No recommendations available.</p>
|
||||
}
|
||||
}
|
||||
|
||||
func hasExtraSidebarDetails(anime jikan.Anime) bool {
|
||||
return anime.TitleJapanese != "" || len(anime.TitleSynonyms) > 0 || len(anime.Studios) > 0 || len(anime.Producers) > 0 || anime.Source != "" || len(anime.Demographics) > 0 || len(anime.Themes) > 0 || anime.Broadcast.String != "" || len(anime.Streaming) > 0
|
||||
}
|
||||
|
||||
@@ -7,28 +7,34 @@ import "fmt"
|
||||
templ Discover() {
|
||||
@Layout("mal - discover") {
|
||||
<div class="discover-container">
|
||||
<div class="tabs">
|
||||
<div class="discover-header">
|
||||
<h1>Discover</h1>
|
||||
<p class="discover-subtitle">Browse what's airing now and what is coming soon.</p>
|
||||
</div>
|
||||
<div class="tabs discover-tabs" data-tab-group="discover">
|
||||
<button
|
||||
class="tab active"
|
||||
type="button"
|
||||
hx-get="/api/discover/airing?page=1"
|
||||
hx-target="#discover-content"
|
||||
hx-trigger="click"
|
||||
onclick="document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); this.classList.add('active');"
|
||||
data-tab-trigger
|
||||
>
|
||||
airing now
|
||||
</button>
|
||||
<button
|
||||
class="tab"
|
||||
type="button"
|
||||
hx-get="/api/discover/upcoming?page=1"
|
||||
hx-target="#discover-content"
|
||||
hx-trigger="click"
|
||||
onclick="document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); this.classList.add('active');"
|
||||
data-tab-trigger
|
||||
>
|
||||
upcoming
|
||||
</button>
|
||||
</div>
|
||||
<div class="catalog-grid" id="discover-content" hx-get="/api/discover/airing?page=1" hx-trigger="load">
|
||||
<div style="grid-column: 1 / -1;">
|
||||
<div class="grid-full-width">
|
||||
@ui.LoadingIndicator("Loading discover")
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,9 @@ templ Layout(title string) {
|
||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg"/>
|
||||
<link rel="stylesheet" href="/static/css/style.css"/>
|
||||
<script src="https://unpkg.com/htmx.org@1.9.11"></script>
|
||||
<script src="/static/js/discover.js" defer></script>
|
||||
<script src="/static/js/schedule.js" defer></script>
|
||||
<script src="/static/js/anime.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
|
||||
@@ -18,7 +18,7 @@ templ Notifications(watching []WatchingAnimeWithDetails) {
|
||||
|
||||
if len(watching) == 0 {
|
||||
@ui.EmptyState("No airing anime in your watching list.") {
|
||||
<span style="font-size: var(--text-sm); margin-top: var(--space-sm); display: block;">Add currently airing shows to your watching list to see upcoming episodes here.</span>
|
||||
<span class="empty-state-hint">Add currently airing shows to your watching list to see upcoming episodes here.</span>
|
||||
}
|
||||
} else {
|
||||
<div class="notifications-list">
|
||||
@@ -28,7 +28,7 @@ templ Notifications(watching []WatchingAnimeWithDetails) {
|
||||
</div>
|
||||
}
|
||||
|
||||
<h1 style="margin-top: var(--space-2xl);">Discovered sequels</h1>
|
||||
<h1 class="notifications-section-title">Discovered sequels</h1>
|
||||
<p class="notifications-subtitle">Because you've watched prequels.</p>
|
||||
|
||||
<div hx-get="/notifications/upcoming" hx-trigger="load, every 15s" hx-swap="innerHTML">
|
||||
@@ -52,7 +52,7 @@ func splitUpcomingSeasons(items []database.GetUpcomingSeasonsRow) (airing []data
|
||||
templ UpcomingSeasonsList(upcomingSeasons []database.GetUpcomingSeasonsRow) {
|
||||
if len(upcomingSeasons) == 0 {
|
||||
@ui.EmptyState("No upcoming seasons for anime you've watched.") {
|
||||
<span style="font-size: var(--text-sm); margin-top: var(--space-sm); display: block;">As you watch more shows, new seasons will appear here.</span>
|
||||
<span class="empty-state-hint">As you watch more shows, new seasons will appear here.</span>
|
||||
}
|
||||
} else {
|
||||
@renderSplitSeasons(upcomingSeasons)
|
||||
@@ -62,8 +62,8 @@ templ UpcomingSeasonsList(upcomingSeasons []database.GetUpcomingSeasonsRow) {
|
||||
templ renderSplitSeasons(upcomingSeasons []database.GetUpcomingSeasonsRow) {
|
||||
if airing, upcoming := splitUpcomingSeasons(upcomingSeasons); true {
|
||||
if len(airing) > 0 {
|
||||
<h2 style="font-size: var(--text-md); margin-bottom: var(--space-md); color: var(--text-muted);">Airing now (not tracked)</h2>
|
||||
<div class="notifications-list" style="margin-bottom: var(--space-xl);">
|
||||
<h2 class="notifications-group-title">Airing now (not tracked)</h2>
|
||||
<div class="notifications-list notifications-list-spaced">
|
||||
for _, item := range airing {
|
||||
@UpcomingSeasonCard(item)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ templ renderSplitSeasons(upcomingSeasons []database.GetUpcomingSeasonsRow) {
|
||||
}
|
||||
|
||||
if len(upcoming) > 0 {
|
||||
<h2 style="font-size: var(--text-md); margin-bottom: var(--space-md); color: var(--text-muted);">Announced & upcoming</h2>
|
||||
<h2 class="notifications-group-title">Announced & upcoming</h2>
|
||||
<div class="notifications-list">
|
||||
for _, item := range upcoming {
|
||||
@UpcomingSeasonCard(item)
|
||||
@@ -94,7 +94,7 @@ templ UpcomingSeasonCard(item database.GetUpcomingSeasonsRow) {
|
||||
{ displaySeasonTitle(item) }
|
||||
</div>
|
||||
<div class="notification-meta">
|
||||
<span class="notification-broadcast" style="color: var(--text-muted) !important;">Because you watched { item.PrequelTitle }</span>
|
||||
<span class="notification-broadcast notification-muted">Because you watched { item.PrequelTitle }</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -11,28 +11,20 @@ templ Schedule() {
|
||||
<h1>Weekly schedule</h1>
|
||||
<p class="schedule-subtitle">Airing times in JST</p>
|
||||
|
||||
<div class="schedule-tabs">
|
||||
<button class="schedule-tab active" data-day="Monday" onclick="loadDay('monday', this)">Mon</button>
|
||||
<button class="schedule-tab" data-day="Tuesday" onclick="loadDay('tuesday', this)">Tue</button>
|
||||
<button class="schedule-tab" data-day="Wednesday" onclick="loadDay('wednesday', this)">Wed</button>
|
||||
<button class="schedule-tab" data-day="Thursday" onclick="loadDay('thursday', this)">Thu</button>
|
||||
<button class="schedule-tab" data-day="Friday" onclick="loadDay('friday', this)">Fri</button>
|
||||
<button class="schedule-tab" data-day="Saturday" onclick="loadDay('saturday', this)">Sat</button>
|
||||
<button class="schedule-tab" data-day="Sunday" onclick="loadDay('sunday', this)">Sun</button>
|
||||
<div class="schedule-tabs" data-tab-group="schedule">
|
||||
<button class="schedule-tab active" type="button" data-day="monday" data-schedule-tab>Mon</button>
|
||||
<button class="schedule-tab" type="button" data-day="tuesday" data-schedule-tab>Tue</button>
|
||||
<button class="schedule-tab" type="button" data-day="wednesday" data-schedule-tab>Wed</button>
|
||||
<button class="schedule-tab" type="button" data-day="thursday" data-schedule-tab>Thu</button>
|
||||
<button class="schedule-tab" type="button" data-day="friday" data-schedule-tab>Fri</button>
|
||||
<button class="schedule-tab" type="button" data-day="saturday" data-schedule-tab>Sat</button>
|
||||
<button class="schedule-tab" type="button" data-day="sunday" data-schedule-tab>Sun</button>
|
||||
</div>
|
||||
|
||||
<div id="schedule-content" hx-get="/api/schedule?day=monday" hx-trigger="load">
|
||||
@ui.LoadingIndicator("Loading schedule")
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function loadDay(day, btn) {
|
||||
document.querySelectorAll('.schedule-tab').forEach(t => t.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
htmx.ajax('GET', '/api/schedule?day=' + day, '#schedule-content');
|
||||
}
|
||||
</script>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,27 +9,30 @@ import (
|
||||
templ Watchlist(entries []database.GetUserWatchListRow, layout string, currentStatus string, sortBy string, sortOrder string) {
|
||||
@Layout("My Watchlist") {
|
||||
<div class="watchlist-header">
|
||||
<h2>Watchlist</h2>
|
||||
<div class="watchlist-heading">
|
||||
<h2>Watchlist</h2>
|
||||
<p class="watchlist-subtitle">Track what you're watching with less noise.</p>
|
||||
</div>
|
||||
<div class="watchlist-controls">
|
||||
<a href="/api/watchlist/export" class="text-link">Export</a>
|
||||
<button class="text-link" onclick="document.getElementById('import-file').click()">Import</button>
|
||||
<form id="import-form" hx-post="/api/watchlist/import" hx-encoding="multipart/form-data" style="display: none;">
|
||||
<button class="text-link" type="button" onclick="document.getElementById('import-file').click()">Import</button>
|
||||
<form id="import-form" hx-post="/api/watchlist/import" hx-encoding="multipart/form-data" class="is-hidden">
|
||||
<input type="file" id="import-file" name="file" accept=".json" onchange="htmx.trigger('#import-form', 'submit')"/>
|
||||
</form>
|
||||
<div class="view-toggle">
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=grid&status=%s&sort=%s&order=%s", currentStatus, sortBy, sortOrder)) } class={ viewClass(layout == "grid") }>Grid</a>
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=table&status=%s&sort=%s&order=%s", currentStatus, sortBy, sortOrder)) } class={ viewClass(layout == "table") }>Table</a>
|
||||
<a href={ templ.URL(watchlistURL("grid", currentStatus, sortBy, sortOrder)) } class={ viewClass(layout == "grid") }>Grid</a>
|
||||
<a href={ templ.URL(watchlistURL("table", currentStatus, sortBy, sortOrder)) } class={ viewClass(layout == "table") }>Table</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-tabs">
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=%s&status=all&sort=%s&order=%s", layout, sortBy, sortOrder)) } class={ tabClass(currentStatus == "all") }>All</a>
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=%s&status=watching&sort=%s&order=%s", layout, sortBy, sortOrder)) } class={ tabClass(currentStatus == "watching") }>Watching</a>
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=%s&status=continuing&sort=%s&order=%s", layout, sortBy, sortOrder)) } class={ tabClass(currentStatus == "continuing") }>Continuing</a>
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=%s&status=on_hold&sort=%s&order=%s", layout, sortBy, sortOrder)) } class={ tabClass(currentStatus == "on_hold") }>On hold</a>
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=%s&status=plan_to_watch&sort=%s&order=%s", layout, sortBy, sortOrder)) } class={ tabClass(currentStatus == "plan_to_watch") }>Plan to watch</a>
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=%s&status=dropped&sort=%s&order=%s", layout, sortBy, sortOrder)) } class={ tabClass(currentStatus == "dropped") }>Dropped</a>
|
||||
<a href={ templ.URL(fmt.Sprintf("/watchlist?view=%s&status=completed&sort=%s&order=%s", layout, sortBy, sortOrder)) } class={ tabClass(currentStatus == "completed") }>Completed</a>
|
||||
<a href={ templ.URL(watchlistURL(layout, "all", sortBy, sortOrder)) } class={ tabClass(currentStatus == "all") }>All</a>
|
||||
<a href={ templ.URL(watchlistURL(layout, "watching", sortBy, sortOrder)) } class={ tabClass(currentStatus == "watching") }>Watching</a>
|
||||
<a href={ templ.URL(watchlistURL(layout, "continuing", sortBy, sortOrder)) } class={ tabClass(currentStatus == "continuing") }>Continuing</a>
|
||||
<a href={ templ.URL(watchlistURL(layout, "on_hold", sortBy, sortOrder)) } class={ tabClass(currentStatus == "on_hold") }>On hold</a>
|
||||
<a href={ templ.URL(watchlistURL(layout, "plan_to_watch", sortBy, sortOrder)) } class={ tabClass(currentStatus == "plan_to_watch") }>Plan to watch</a>
|
||||
<a href={ templ.URL(watchlistURL(layout, "dropped", sortBy, sortOrder)) } class={ tabClass(currentStatus == "dropped") }>Dropped</a>
|
||||
<a href={ templ.URL(watchlistURL(layout, "completed", sortBy, sortOrder)) } class={ tabClass(currentStatus == "completed") }>Completed</a>
|
||||
</div>
|
||||
@ui.SortFilter(ui.SortFilterOptions{Sort: sortBy, Order: sortOrder, View: layout, Status: currentStatus})
|
||||
if len(entries) == 0 {
|
||||
@@ -89,7 +92,6 @@ templ Watchlist(entries []database.GetUserWatchListRow, layout string, currentSt
|
||||
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"
|
||||
style="background: none; border: none; cursor: pointer;"
|
||||
>Remove</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -114,3 +116,7 @@ func tabClass(active bool) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user