127 lines
4.7 KiB
Plaintext
127 lines
4.7 KiB
Plaintext
{{define "title"}}Discover{{end}}
|
|
{{define "content"}}
|
|
<script>
|
|
let isFetchingRandom = false;
|
|
|
|
async function handleSurpriseMe() {
|
|
if (isFetchingRandom) return;
|
|
isFetchingRandom = true;
|
|
const btn = document.getElementById('surprise-btn');
|
|
const spinner = document.getElementById('surprise-spinner');
|
|
const text = document.getElementById('surprise-text');
|
|
try {
|
|
const res = await fetch(`/api/jikan/random/anime?t=${Date.now()}`, {
|
|
cache: 'no-store'
|
|
});
|
|
if (!res.ok) throw new Error('Failed to fetch random anime');
|
|
const json = await res.json();
|
|
if (json.data && json.data.mal_id) {
|
|
window.location.href = `/anime/${json.data.mal_id}`;
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
} finally {
|
|
isFetchingRandom = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="flex flex-col gap-12 pb-12">
|
|
<section class="relative flex flex-col items-center justify-center overflow-hidden rounded-2xl bg-background-surface px-6 py-24 text-center ring-1 ring-border">
|
|
<div class="from-accent/10 absolute inset-0 bg-linear-to-b to-transparent opacity-50"></div>
|
|
<div class="relative z-10 flex max-w-2xl flex-col items-center gap-6">
|
|
<h1 class="text-4xl font-normal tracking-tight text-foreground sm:text-5xl">
|
|
Don't know what to watch?
|
|
</h1>
|
|
<p class="text-lg text-foreground-muted">
|
|
Let us pick something for you from our vast collection of anime.
|
|
</p>
|
|
<button
|
|
id="surprise-btn"
|
|
class="group bg-accent relative inline-flex items-center justify-center gap-2 overflow-hidden rounded-full px-8 py-4 font-medium text-on-accent transition-transform hover:scale-105 active:scale-95 disabled:opacity-70 disabled:hover:scale-100"
|
|
onclick="handleSurpriseMe()"
|
|
>
|
|
<span id="surprise-spinner" class="hidden h-5 w-5 animate-spin rounded-full border-2 border-on-accent border-t-transparent"></span>
|
|
<svg id="surprise-icon" class="h-5 w-5 transition-transform group-hover:rotate-12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
|
|
</svg>
|
|
<span id="surprise-text">Surprise Me</span>
|
|
</button>
|
|
</div>
|
|
</section>
|
|
|
|
{{/* Trending Section */}}
|
|
<section class="flex flex-col gap-4">
|
|
<div class="flex items-center justify-between">
|
|
<h2 class="text-xl font-normal text-foreground">Trending This Season</h2>
|
|
<a href="/browse?order_by=popularity&sort=desc" class="text-accent text-sm hover:underline">View all</a>
|
|
</div>
|
|
<div hx-get="/api/discover/trending" hx-trigger="load" hx-swap="outerHTML">
|
|
{{template "discover_skeleton"}}
|
|
</div>
|
|
</section>
|
|
|
|
{{/* Upcoming Section */}}
|
|
<section class="flex flex-col gap-4">
|
|
<div class="flex items-center justify-between">
|
|
<h2 class="text-xl font-normal text-foreground">Highly Anticipated</h2>
|
|
<a href="/browse?status=upcoming&order_by=members&sort=desc" class="text-accent text-sm hover:underline">View all</a>
|
|
</div>
|
|
<div hx-get="/api/discover/upcoming" hx-trigger="load" hx-swap="outerHTML">
|
|
{{template "discover_skeleton"}}
|
|
</div>
|
|
</section>
|
|
|
|
{{/* Top Section */}}
|
|
<section class="flex flex-col gap-4">
|
|
<div class="flex items-center justify-between">
|
|
<h2 class="text-xl font-normal text-foreground">All-Time Greats</h2>
|
|
<a href="/browse?order_by=score&sort=desc" class="text-accent text-sm hover:underline">View all</a>
|
|
</div>
|
|
<div hx-get="/api/discover/top" hx-trigger="load" hx-swap="outerHTML">
|
|
{{template "discover_skeleton"}}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<style>
|
|
.discover-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
.skeleton {
|
|
background: light-dark(
|
|
linear-gradient(90deg, #f3f4f6 25%, #e5e7eb 50%, #f3f4f6 75%),
|
|
linear-gradient(90deg, #1f1f1f 25%, #2a2a2a 50%, #1f1f1f 75%)
|
|
);
|
|
background-size: 200% 100%;
|
|
animation: skeleton-loading 1.5s infinite;
|
|
}
|
|
@keyframes skeleton-loading {
|
|
0% { background-position: 200% 0; }
|
|
100% { background-position: -200% 0; }
|
|
}
|
|
</style>
|
|
{{end}}
|
|
|
|
{{define "discover_section"}}
|
|
<div class="discover-grid">
|
|
{{range .Animes}}
|
|
{{template "anime_card" dict "Anime" . "WithActions" true "IsWatchlist" (index $.WatchlistMap .MalID)}}
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{define "discover_skeleton"}}
|
|
<div class="discover-grid">
|
|
{{range (seq 8)}}
|
|
<div class="flex flex-col gap-2">
|
|
<div class="skeleton aspect-2/3 w-full rounded-xl"></div>
|
|
<div class="skeleton h-4 w-3/4 rounded"></div>
|
|
<div class="skeleton h-3 w-1/2 rounded opacity-50"></div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|