Files
mal/web/templates/anime.templ

175 lines
6.8 KiB
Plaintext

package templates
import (
"fmt"
"strings"
"mal/integrations/jikan"
animecomponents "mal/web/components/anime"
"mal/web/components"
watchlistcomponents "mal/web/components/watchlist"
"mal/web/shared"
)
templ AnimeDetails(anime jikan.Anime, currentStatus string, nextEpisode int) {
@Layout("mal - " + anime.DisplayTitle(), true) {
<div class="grid items-start gap-5 xl:grid-cols-[minmax(0,1fr)_300px]">
<div class="grid min-w-0 gap-8">
<div class="grid gap-5 lg:grid-cols-[220px_minmax(0,1fr)]">
<div class="w-56">
if anime.ImageURL() != "" {
<img class="w-full" src={ anime.ImageURL() } alt={ anime.DisplayTitle() }/>
} else {
<div class="flex aspect-2/3 max-h-(--poster-max-height) w-full justify-center overflow-hidden text-transparent">No image</div>
}
</div>
<div>
<h1>{ anime.DisplayTitle() }</h1>
if anime.TitleJapanese != "" {
<p class="my-2 mb-3 text-sm text-(--text-muted)">{ anime.TitleJapanese }</p>
}
<div class="flex flex-wrap gap-2">
if anime.ShortRating() != "" {
<span class="text-xs text-(--text-faint)">{ anime.ShortRating() }</span>
}
if anime.Type != "" {
<span class="text-xs text-(--text-faint)">{ anime.Type }</span>
}
if anime.Episodes > 0 {
<span class="text-xs text-(--text-faint)">{ fmt.Sprintf("%d ep", anime.Episodes) }</span>
}
if anime.ShortDuration() != "" {
<span class="text-xs text-(--text-faint)">{ anime.ShortDuration() }</span>
}
</div>
<div class="mt-3">
<div class="flex flex-wrap items-center gap-2">
@watchlistcomponents.WatchlistDropdown(anime.MalID, anime.Title, anime.TitleEnglish, anime.TitleJapanese, anime.ImageURL(), currentStatus, anime.Airing)
<a
href={ templ.URL(fmt.Sprintf("/watch/%d/%d", anime.MalID, shared.WatchTargetEpisode(currentStatus, nextEpisode))) }
class="inline-flex h-8 items-center bg-(--panel-soft) px-2 text-xs text-(--text) no-underline hover:text-(--text) hover:no-underline"
>Watch</a>
</div>
</div>
<section class="mt-4 max-w-4xl">
if anime.Synopsis != "" {
<p>{ anime.Synopsis }</p>
} else {
<p class="text-(--text-faint)">No synopsis available.</p>
}
</section>
</div>
</div>
<section>
<h3 class="mb-3 text-lg font-semibold tracking-wide text-(--text)">Related</h3>
<div hx-get={ string(templ.URL(fmt.Sprintf("/api/anime/%d/relations", anime.MalID))) } hx-trigger="load">
@components.LoadingIndicator("Loading relations")
</div>
</section>
<section>
<h3 class="mb-3 text-lg font-semibold tracking-wide text-(--text)">Recommendations</h3>
<div hx-get={ string(templ.URL(fmt.Sprintf("/api/anime/%d/recommendations", anime.MalID))) } hx-trigger="load">
@components.LoadingIndicator("Loading recommendations")
</div>
</section>
</div>
<aside class="sticky top-20 grid gap-4 bg-(--panel) p-3 max-xl:static">
<div class="grid gap-3">
<h3 class="mb-2 text-base font-semibold tracking-wide text-(--text)">Details</h3>
if anime.Aired.String != "" {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Aired</span>
<span class="text-sm text-(--text-muted)">{ anime.Aired.String }</span>
</div>
}
if anime.Premiered() != "" {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Premiered</span>
<span class="text-sm text-(--text-muted)">{ anime.Premiered() }</span>
</div>
}
if anime.Status != "" {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Status</span>
<span class="text-sm text-(--text-muted)">{ anime.Status }</span>
</div>
}
if anime.Duration != "" {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Duration</span>
<span class="text-sm text-(--text-muted)">{ anime.Duration }</span>
</div>
}
if len(anime.Genres) > 0 {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Genres</span>
<span class="text-sm text-(--text-muted)">{ shared.JoinNames(anime.Genres) }</span>
</div>
}
</div>
if shared.HasExtraSidebarDetails(anime) {
<details class="grid gap-3">
<summary class="cursor-pointer text-xs text-(--text-muted)">More metadata</summary>
if anime.TitleJapanese != "" {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Japanese</span>
<span class="text-sm text-(--text-muted)">{ anime.TitleJapanese }</span>
</div>
}
if len(anime.TitleSynonyms) > 0 {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Synonyms</span>
<span class="text-sm text-(--text-muted)">{ strings.Join(anime.TitleSynonyms, ", ") }</span>
</div>
}
if len(anime.Studios) > 0 {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Studios</span>
<span class="text-sm text-(--text-muted)">
@animecomponents.StudioLinks(anime.Studios)
</span>
</div>
}
if len(anime.Producers) > 0 {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Producers</span>
<span class="text-sm text-(--text-muted)">{ shared.JoinNames(anime.Producers) }</span>
</div>
}
if anime.Source != "" {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Source</span>
<span class="text-sm text-(--text-muted)">{ anime.Source }</span>
</div>
}
if len(anime.Demographics) > 0 {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Demographics</span>
<span class="text-sm text-(--text-muted)">{ shared.JoinNames(anime.Demographics) }</span>
</div>
}
if len(anime.Themes) > 0 {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Themes</span>
<span class="text-sm text-(--text-muted)">{ shared.JoinNames(anime.Themes) }</span>
</div>
}
if anime.Broadcast.String != "" {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Broadcast</span>
<span class="text-sm text-(--text-muted)" data-jst-text={ anime.Broadcast.String }>{ anime.Broadcast.String }</span>
</div>
}
if len(anime.Streaming) > 0 {
<div class="mt-1 grid gap-1">
<span class="mt-0.5 text-sm text-(--text-faint)">Streaming</span>
<span class="text-sm text-(--text-muted)">{ shared.JoinStreamingNames(anime) }</span>
</div>
}
</details>
}
</aside>
</div>
}
}