Files
mal/internal/templates/notifications.templ

164 lines
5.0 KiB
Plaintext

package templates
import "mal/internal/jikan"
import "mal/internal/database"
import "fmt"
type WatchingAnimeWithDetails struct {
Entry database.GetWatchingAnimeRow
Anime jikan.Anime
}
templ Notifications(watching []WatchingAnimeWithDetails) {
@Layout("mal - notifications") {
<div class="notifications-page">
<h1>airing shows (tracking)</h1>
<p class="notifications-subtitle">shows you're currently watching or planning to watch</p>
if len(watching) == 0 {
<div class="no-notifications">
<p>no airing anime in your watching list</p>
<p class="hint">add currently airing shows to your watching list to see upcoming episodes here</p>
</div>
} else {
<div class="notifications-list">
for _, item := range watching {
@NotificationCard(item)
}
</div>
}
<h1 style="margin-top: var(--space-2xl);">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">
<div class="loading-indicator">
<div class="loading-dot"></div><div class="loading-dot"></div><div class="loading-dot"></div>
<span>syncing sequel graphs...</span>
</div>
</div>
</div>
}
}
templ UpcomingSeasonsList(upcomingSeasons []database.GetUpcomingSeasonsRow) {
// Split into Airing vs Upcoming
var airing []database.GetUpcomingSeasonsRow
var upcoming []database.GetUpcomingSeasonsRow
for _, item := range upcomingSeasons {
if item.Status.Valid && item.Status.String == "Currently Airing" {
airing = append(airing, item)
} else {
upcoming = append(upcoming, item)
}
}
if len(upcomingSeasons) == 0 {
<div class="no-notifications">
<p>no upcoming seasons for anime you've watched</p>
<p class="hint">as you watch more shows, new seasons will appear here</p>
</div>
} else {
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);">
for _, item := range airing {
@UpcomingSeasonCard(item)
}
</div>
}
if len(upcoming) > 0 {
<h2 style="font-size: var(--text-md); margin-bottom: var(--space-md); color: var(--text-muted);">announced & upcoming</h2>
<div class="notifications-list">
for _, item := range upcoming {
@UpcomingSeasonCard(item)
}
</div>
}
}
}
templ UpcomingSeasonCard(item database.GetUpcomingSeasonsRow) {
<a href={ templ.URL(fmt.Sprintf("/anime/%d", item.ID)) } class="notification-card">
<div class="notification-image">
if item.ImageUrl != "" {
<img src={ item.ImageUrl } alt={ displaySeasonTitle(item) } loading="lazy"/>
} else {
<div class="no-image">no image</div>
}
</div>
<div class="notification-content">
<div class="notification-title">
{ displaySeasonTitle(item) }
</div>
<div class="notification-meta">
<span class="notification-broadcast" style="color: var(--text-muted) !important;">because you watched { item.PrequelTitle }</span>
</div>
</div>
</a>
}
func displaySeasonTitle(entry database.GetUpcomingSeasonsRow) string {
if entry.TitleEnglish.Valid && entry.TitleEnglish.String != "" {
return entry.TitleEnglish.String
}
if entry.TitleJapanese.Valid && entry.TitleJapanese.String != "" {
return entry.TitleJapanese.String
}
return entry.TitleOriginal
}
templ NotificationCard(item WatchingAnimeWithDetails) {
<a href={ templ.URL(fmt.Sprintf("/anime/%d", item.Entry.AnimeID)) } class="notification-card">
<div class="notification-image">
if item.Entry.ImageUrl != "" {
<img src={ item.Entry.ImageUrl } alt={ displayTitle(item.Entry) } loading="lazy"/>
} else {
<div class="no-image">no image</div>
}
</div>
<div class="notification-content">
<div class="notification-title">
{ displayTitle(item.Entry) }
</div>
<div class="notification-meta">
if item.Anime.Broadcast.String != "" {
<span class="notification-broadcast">{ item.Anime.Broadcast.String }</span>
}
if item.Anime.Episodes > 0 {
<span class="notification-progress">
if item.Entry.CurrentEpisode.Valid {
{ fmt.Sprintf("%d / %d eps", item.Entry.CurrentEpisode.Int64, item.Anime.Episodes) }
} else {
{ fmt.Sprintf("0 / %d eps", item.Anime.Episodes) }
}
</span>
} else if item.Entry.CurrentEpisode.Valid && item.Entry.CurrentEpisode.Int64 > 0 {
<span class="notification-progress">
{ fmt.Sprintf("%d eps watched", item.Entry.CurrentEpisode.Int64) }
</span>
}
</div>
</div>
</a>
}
func displayTitle(entry database.GetWatchingAnimeRow) string {
if entry.TitleEnglish.Valid && entry.TitleEnglish.String != "" {
return entry.TitleEnglish.String
}
if entry.TitleJapanese.Valid && entry.TitleJapanese.String != "" {
return entry.TitleJapanese.String
}
return entry.TitleOriginal
}
func truncate(s string, max int) string {
if len(s) <= max {
return s
}
return s[:max-3] + "..."
}