feat: add schedule page
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
"home" (dict "href" "/" "label" "Home")
|
"home" (dict "href" "/" "label" "Home")
|
||||||
"browse" (dict "href" "/browse" "label" "Browse")
|
"browse" (dict "href" "/browse" "label" "Browse")
|
||||||
"discover" (dict "href" "/discover" "label" "Discover")
|
"discover" (dict "href" "/discover" "label" "Discover")
|
||||||
|
"schedule" (dict "href" "/schedule" "label" "Schedule")
|
||||||
"watchlist" (dict "href" "/watchlist" "label" "Watchlist")
|
"watchlist" (dict "href" "/watchlist" "label" "Watchlist")
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -81,6 +82,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
{{/* Schedule */}}
|
||||||
|
{{$isActive := eq $currentPath "/schedule"}}
|
||||||
|
<a href="/schedule" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Schedule"{{end}} aria-current="{{if $isActive}}page{{end}}">
|
||||||
|
{{if $isActive}}
|
||||||
|
<div class="bg-accent absolute top-1/2 left-0 h-12 w-0.5 -translate-y-1/2 rounded-r-sm"></div>
|
||||||
|
{{end}}
|
||||||
|
<svg class="size-6 shrink-0 transition-colors duration-200 {{if $isActive}}text-accent{{else}}text-foreground-muted group-hover:text-foreground{{end}}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<rect x="3" y="4" width="18" height="18" rx="2" />
|
||||||
|
<line x1="16" y1="2" x2="16" y2="6" />
|
||||||
|
<line x1="8" y1="2" x2="8" y2="6" />
|
||||||
|
<line x1="3" y1="10" x2="21" y2="10" />
|
||||||
|
</svg>
|
||||||
|
<div class="nav-label-container grid grid-cols-[1fr] opacity-100 ml-4">
|
||||||
|
<div class="overflow-hidden min-w-0">
|
||||||
|
<span class="whitespace-nowrap text-sm font-medium transition-colors duration-200 {{if $isActive}}text-accent{{else}}text-foreground-muted group-hover:text-foreground{{end}}">Schedule</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
{{/* Watchlist */}}
|
{{/* Watchlist */}}
|
||||||
{{$isActive := eq $currentPath "/watchlist"}}
|
{{$isActive := eq $currentPath "/watchlist"}}
|
||||||
<a href="/watchlist" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Watchlist"{{end}} aria-current="{{if $isActive}}page{{end}}">
|
<a href="/watchlist" class="group relative flex items-center px-7 py-3 transition-colors hover:bg-surface-hover" {{if $isCollapsed}}title="Watchlist"{{end}} aria-current="{{if $isActive}}page{{end}}">
|
||||||
|
|||||||
113
templates/schedule.gohtml
Normal file
113
templates/schedule.gohtml
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
{{define "title"}}Schedule{{end}}
|
||||||
|
{{define "content"}}
|
||||||
|
<div class="flex flex-col gap-6 pb-12">
|
||||||
|
<section class="flex items-end justify-between gap-4">
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<h1 class="text-2xl font-normal tracking-[-0.02em] text-foreground">Airing Schedule</h1>
|
||||||
|
<p class="text-sm text-foreground-muted">Shows from your watchlist that are currently airing.</p>
|
||||||
|
</div>
|
||||||
|
<a href="/watchlist" class="text-sm text-foreground-muted transition-colors hover:text-foreground">Manage watchlist</a>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div hx-get="/api/schedule" hx-trigger="load" hx-swap="outerHTML">
|
||||||
|
{{template "schedule_skeleton"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "schedule_section"}}
|
||||||
|
<section class="flex w-full flex-col gap-4" data-schedule-section>
|
||||||
|
{{if eq (len .Animes) 0}}
|
||||||
|
<div class="bg-background-surface p-10 ring-1 ring-black/5">
|
||||||
|
<div class="mx-auto flex max-w-xl flex-col items-center gap-3 text-center">
|
||||||
|
<h2 class="text-base font-medium text-foreground">Nothing airing yet</h2>
|
||||||
|
<p class="text-sm text-foreground-muted">Add currently airing shows to your watchlist to see their weekly broadcast time here.</p>
|
||||||
|
<div class="mt-2 flex flex-wrap items-center justify-center gap-3">
|
||||||
|
<a href="/browse?status=airing" class="inline-flex h-10 items-center justify-center bg-background-button px-4 text-sm font-normal text-foreground transition-colors hover:bg-background-button-hover focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent">Browse airing</a>
|
||||||
|
<a href="/discover" class="inline-flex h-10 items-center justify-center bg-transparent px-4 text-sm font-normal text-foreground-muted transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent">Discover</a>
|
||||||
|
<a href="/watchlist" class="inline-flex h-10 items-center justify-center bg-transparent px-4 text-sm font-normal text-foreground-muted transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent">Open watchlist</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="grid gap-3 sm:[grid-template-columns:repeat(auto-fit,minmax(420px,1fr))] xl:[grid-template-columns:repeat(auto-fit,minmax(520px,1fr))]">
|
||||||
|
{{range .Animes}}
|
||||||
|
{{$anime := .}}
|
||||||
|
<div class="bg-background-surface p-5 ring-1 ring-black/5" data-notification-content>
|
||||||
|
<div class="flex gap-5">
|
||||||
|
<a href="/anime/{{$anime.MalID}}" class="shrink-0 overflow-hidden bg-background">
|
||||||
|
{{$imageUrl := "https://placehold.co/200x300?text=No+Image"}}
|
||||||
|
{{if $anime.Images.Webp.LargeImageURL}}
|
||||||
|
{{$imageUrl = $anime.Images.Webp.LargeImageURL}}
|
||||||
|
{{else if $anime.Images.Jpg.LargeImageURL}}
|
||||||
|
{{$imageUrl = $anime.Images.Jpg.LargeImageURL}}
|
||||||
|
{{end}}
|
||||||
|
<img src="{{$imageUrl}}" alt="{{$anime.DisplayTitle}}" class="h-32 w-24 object-cover" loading="lazy" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="min-w-0 flex-1">
|
||||||
|
<div class="flex items-start justify-between gap-2">
|
||||||
|
<a href="/anime/{{$anime.MalID}}" class="min-w-0">
|
||||||
|
<h3 class="line-clamp-2 text-base font-medium text-foreground">{{$anime.DisplayTitle}}</h3>
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-watchlist-toggle
|
||||||
|
data-mal-id="{{$anime.MalID}}"
|
||||||
|
data-watchlist-title="{{$anime.DisplayTitle}}"
|
||||||
|
class="shrink-0 text-accent hover:text-accent/80 transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent disabled:opacity-50 {{if (index $.WatchlistMap $anime.MalID)}}in-watchlist{{end}}"
|
||||||
|
aria-label="{{if (index $.WatchlistMap $anime.MalID)}}Remove from Watchlist{{else}}Add to Watchlist{{end}}"
|
||||||
|
>
|
||||||
|
<svg class="size-5 watchlist-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z" /></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-foreground-muted">
|
||||||
|
{{if $anime.Type}}<span>{{$anime.Type}}</span>{{end}}
|
||||||
|
{{if $anime.Year}}<span>•</span><span>{{$anime.Year}}</span>{{end}}
|
||||||
|
{{if $anime.Episodes}}<span>•</span><span>{{$anime.Episodes}} ep</span>{{end}}
|
||||||
|
{{if $anime.Score}}<span>•</span><span class="flex items-center gap-1"><svg class="text-accent h-3 w-3" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>{{$anime.Score}}</span>{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3 flex flex-col gap-1.5 text-sm text-foreground-muted">
|
||||||
|
{{if $anime.Broadcast.String}}
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="shrink-0 font-medium text-foreground">Broadcast</span>
|
||||||
|
<span class="min-w-0 truncate" data-jst-text="{{$anime.Broadcast.String}}" data-broadcast-day="{{$anime.Broadcast.Day}}" data-broadcast-time="{{$anime.Broadcast.Time}}" data-broadcast-timezone="{{$anime.Broadcast.Timezone}}">{{$anime.Broadcast.String}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="shrink-0 font-medium text-foreground">Next</span>
|
||||||
|
<span data-next-airing class="min-w-0 truncate">—</span>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="shrink-0 font-medium text-foreground">Broadcast</span>
|
||||||
|
<span class="min-w-0 truncate">Unknown</span>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</section>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "schedule_skeleton"}}
|
||||||
|
<section class="grid w-full gap-3 sm:[grid-template-columns:repeat(auto-fit,minmax(420px,1fr))] xl:[grid-template-columns:repeat(auto-fit,minmax(520px,1fr))]">
|
||||||
|
{{range (seq 6)}}
|
||||||
|
<div class="bg-background-surface p-5 ring-1 ring-black/5">
|
||||||
|
<div class="flex gap-5">
|
||||||
|
<div class="h-32 w-24 bg-background-button animate-pulse"></div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="h-4 w-3/4 rounded bg-background-button animate-pulse"></div>
|
||||||
|
<div class="mt-3 h-3 w-2/3 rounded bg-background-button animate-pulse opacity-70"></div>
|
||||||
|
<div class="mt-3 h-3 w-1/2 rounded bg-background-button animate-pulse opacity-70"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</section>
|
||||||
|
{{end}}
|
||||||
Reference in New Issue
Block a user