176 lines
6.9 KiB
Plaintext
176 lines
6.9 KiB
Plaintext
package templates
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"mal/integrations/jikan"
|
|
animecomponents "mal/web/components/anime"
|
|
components "mal/web/components"
|
|
watchlistcomponents "mal/web/components/watchlist"
|
|
"mal/web/shared"
|
|
"mal/web/shared/layout"
|
|
)
|
|
|
|
templ AnimeDetails(anime jikan.Anime, currentStatus string, nextEpisode int) {
|
|
@layout.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>
|
|
}
|
|
}
|