Files
mal/web/components/anime_card.templ

118 lines
3.4 KiB
Plaintext

package ui
import (
"fmt"
"mal/web/components/watchlist"
)
type AnimeCardProps struct {
ID int
Title string
ImageURL string
Href string
Class string
ImgClass string
TitleClass string
HideTitle bool
CurrentNode bool
Synopsis string
PlayHref string
TitleEnglish string
TitleJapanese string
Airing bool
WatchlistStatus string
DisableWatchlist bool
}
templ AnimeCard(props AnimeCardProps) {
<div class={ defaultString(props.Class, "group min-w-0") }>
@animeCardPoster(props)
if !props.HideTitle {
if props.CurrentNode {
<div class={ defaultString(props.TitleClass, "mt-2 line-clamp-2 text-sm leading-snug text-(--text)") }>
{ props.Title }
</div>
} else {
<a href={ templ.URL(cardHref(props)) } class="block">
<div class={ defaultString(props.TitleClass, "mt-2 line-clamp-2 text-sm leading-snug text-(--text)") }>
{ props.Title }
</div>
</a>
}
}
{ children... }
</div>
}
func cardHref(props AnimeCardProps) string {
if props.Href != "" {
return props.Href
}
return fmt.Sprintf("/anime/%d", props.ID)
}
templ animeCardPoster(props AnimeCardProps) {
<div class="relative grid w-full aspect-2/3 overflow-hidden">
<div class="col-start-1 row-start-1 h-full w-full">
@animeCardImage(props)
</div>
<div class="pointer-events-none col-start-1 row-start-1 bg-black/0 transition-colors duration-200 group-hover:bg-black/40"></div>
if props.Synopsis != "" {
<div class="pointer-events-none col-start-1 row-start-1 flex flex-col justify-between p-3 opacity-0 transition-opacity duration-200 group-hover:opacity-100">
<div>
<div class="mb-1 text-[11px] font-semibold text-white/90">{ props.Title }</div>
<p class="line-clamp-3 text-[11px] leading-relaxed text-white/90">{ props.Synopsis }</p>
</div>
</div>
}
if !props.CurrentNode {
<a href={ templ.URL(cardHref(props)) } class="absolute inset-0 z-10" aria-label={ props.Title }></a>
}
if props.PlayHref != "" || !props.CurrentNode && !props.DisableWatchlist {
<div class="pointer-events-none col-start-1 row-start-1 z-20 flex items-end justify-start p-3 opacity-0 transition-opacity duration-200 group-hover:opacity-100">
<div class="pointer-events-auto flex gap-2">
if props.PlayHref != "" {
<a
href={ templ.URL(props.PlayHref) }
class="text-white"
aria-label="Play"
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>Play</title>
<path d="M8 5V19L19 12L8 5Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
</svg>
</a>
}
if !props.CurrentNode && !props.DisableWatchlist {
@watchlist.CardButton(
props.ID,
props.Title,
props.TitleEnglish,
props.TitleJapanese,
props.ImageURL,
props.Airing,
props.WatchlistStatus != "",
)
}
</div>
</div>
}
</div>
}
templ animeCardImage(props AnimeCardProps) {
if props.ImageURL != "" {
<img src={ props.ImageURL } alt={ props.Title } class={ defaultString(props.ImgClass, "block h-full w-full object-cover object-center") } loading="lazy"/>
} else {
<div class="flex h-full w-full justify-center overflow-hidden text-transparent">No image</div>
}
}
func defaultString(val, fallback string) string {
if val == "" {
return fallback
}
return val
}