ui: declutter anime pages and controls

This commit is contained in:
2026-04-10 01:15:19 +02:00
parent 8965dc5441
commit e2fc44bf1a
12 changed files with 425 additions and 168 deletions

View File

@@ -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
}