aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-01-27 00:06:16 -0800
committerFuwn <[email protected]>2026-01-27 00:06:16 -0800
commit6629a6ae5227ddec97d9870e9f800b129e4d2d7b (patch)
treec18f0b3a70e2ad78a4b46b52eb123599308e1793 /src
parentfeat(+layout.svelte): Add Web Analytics (diff)
downloaddue.moe-6629a6ae5227ddec97d9870e9f800b129e4d2d7b.tar.xz
due.moe-6629a6ae5227ddec97d9870e9f800b129e4d2d7b.zip
feat: Add hero for landing and welcome page
Diffstat (limited to 'src')
-rw-r--r--src/lib/LandingHero.svelte175
-rw-r--r--src/routes/+page.svelte5
-rw-r--r--src/routes/welcome/+page.svelte6
3 files changed, 186 insertions, 0 deletions
diff --git a/src/lib/LandingHero.svelte b/src/lib/LandingHero.svelte
new file mode 100644
index 00000000..b42b91ac
--- /dev/null
+++ b/src/lib/LandingHero.svelte
@@ -0,0 +1,175 @@
+<script lang="ts">
+ import { env } from '$env/dynamic/public';
+ import localforage from 'localforage';
+ import { onMount } from 'svelte';
+
+ let visible = $state(false);
+
+ onMount(() => {
+ visible = true;
+ });
+</script>
+
+<section class="hero" class:visible>
+ <div class="hero-content">
+ <p class="tagline">The AniList Companion</p>
+
+ <h1 class="headline">Never miss what's due.</h1>
+
+ <p class="subheadline">
+ Track airing episodes, new manga chapters, and subtitle releases—all in one place.
+
+ <br />
+ <br />
+
+ AniList keeps your list. <strong>due.moe</strong> keeps you current.
+ </p>
+
+ <a
+ class="cta"
+ href={`https://anilist.co/api/v2/oauth/authorize?client_id=${env.PUBLIC_ANILIST_CLIENT_ID}&redirect_uri=${env.PUBLIC_ANILIST_REDIRECT_URI}&response_type=code`}
+ onclick={async () => {
+ await localforage.setItem(
+ 'redirect',
+ window.location.origin + window.location.pathname + window.location.search
+ );
+ }}
+ >
+ Connect with AniList
+ </a>
+ </div>
+
+ <div class="scroll-indicator">
+ <span class="scroll-text">See More</span>
+ <span class="scroll-arrow">↓</span>
+ </div>
+</section>
+
+<style>
+ .hero {
+ min-height: calc(100vh - 8rem);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ padding: 2rem;
+ position: relative;
+ opacity: 0;
+ transform: translateY(20px);
+ transition:
+ opacity 0.6s ease,
+ transform 0.6s ease;
+ }
+
+ .hero.visible {
+ opacity: 1;
+ transform: translateY(0);
+ }
+
+ /*.hero-content {
+ max-width: 640px;
+ }*/
+
+ .tagline {
+ font-size: 0.85rem;
+ /*text-transform: uppercase;*/
+ letter-spacing: 0.15em;
+ color: var(--base04);
+ margin: 0 0 1rem 0;
+ font-weight: 500;
+ }
+
+ .headline {
+ font-size: clamp(2.5rem, 8vw, 4.5rem);
+ font-weight: 700;
+ margin: 0 0 1.5rem 0;
+ color: var(--base06);
+ line-height: 1.1;
+ letter-spacing: -0.02em;
+ }
+
+ .subheadline {
+ font-size: 1.15rem;
+ color: var(--base04);
+ margin: 0 0 2.5rem 0;
+ line-height: 1.6;
+ }
+
+ .subheadline strong {
+ color: var(--base06);
+ font-weight: 600;
+ }
+
+ .cta {
+ display: inline-block;
+ padding: 0.9rem 2rem;
+ background-color: var(--base06);
+ color: var(--base00);
+ font-weight: 600;
+ font-size: 0.95rem;
+ border-radius: 6px;
+ text-decoration: none;
+ transition:
+ transform 0.2s ease,
+ box-shadow 0.2s ease;
+ }
+
+ .cta:hover {
+ text-decoration: none;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+ }
+
+ .cta:active {
+ transform: translateY(0);
+ }
+
+ .scroll-indicator {
+ position: absolute;
+ bottom: 2rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.5rem;
+ color: var(--base03);
+ animation: float 2s ease-in-out infinite;
+ }
+
+ .scroll-text {
+ font-size: 0.75rem;
+ /*text-transform: uppercase;*/
+ letter-spacing: 0.1em;
+ }
+
+ .scroll-arrow {
+ font-size: 1.25rem;
+ }
+
+ @keyframes float {
+ 0%,
+ 100% {
+ transform: translateY(0);
+ }
+
+ 50% {
+ transform: translateY(6px);
+ }
+ }
+
+ @media (max-width: 600px) {
+ .hero {
+ min-height: calc(100vh - 6rem);
+ padding: 1.5rem;
+ }
+
+ .subheadline {
+ font-size: 1rem;
+ }
+
+ .cta {
+ width: 100%;
+ text-align: center;
+ }
+ }
+</style>
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 987e39b2..a66d10c2 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -12,6 +12,7 @@
import Skeleton from '$lib/Loading/Skeleton.svelte';
import locale from '$stores/locale.js';
import Landing from '$lib/Landing.svelte';
+ import LandingHero from '$lib/LandingHero.svelte';
import IndexColumn from '$lib/List/Anime/DueIndexColumn.svelte';
import stateBin from '$stores/stateBin.js';
@@ -33,6 +34,10 @@
<LastActivity user={data.user} />
{#if data.user === undefined}
+ <LandingHero />
+
+ <Spacer />
+
<div class="card">Please log in to view due media.</div>
<Spacer />
diff --git a/src/routes/welcome/+page.svelte b/src/routes/welcome/+page.svelte
index 603e1305..3e15ab26 100644
--- a/src/routes/welcome/+page.svelte
+++ b/src/routes/welcome/+page.svelte
@@ -1,5 +1,11 @@
<script>
import Landing from '$lib/Landing.svelte';
+ import LandingHero from '$lib/LandingHero.svelte';
+ import Spacer from '$lib/Layout/Spacer.svelte';
</script>
+<LandingHero />
+
+<Spacer />
+
<Landing />