From 88f21e268cc17dcc184cf4b1c70c104d1442feb3 Mon Sep 17 00:00:00 2001
From: Fuwn <contact@fuwn.net>
Date: Sun, 22 Mar 2026 04:01:25 +0000
Subject: perf: lazy-load landing demo sections

---
 src/lib/Landing.svelte | 96 ++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 81 insertions(+), 15 deletions(-)

(limited to 'src/lib/Landing.svelte')

diff --git a/src/lib/Landing.svelte b/src/lib/Landing.svelte
index dd493be4..604becee 100644
--- a/src/lib/Landing.svelte
+++ b/src/lib/Landing.svelte
@@ -1,8 +1,6 @@
 <script lang="ts">
 import root from "./Utility/root";
 import { env } from "$env/dynamic/public";
-import CompletedAnimeList from "./List/Anime/CompletedAnimeList.svelte";
-import MangaListTemplate from "./List/Manga/MangaListTemplate.svelte";
 import localforage from "localforage";
 import { onMount } from "svelte";
 
@@ -11,10 +9,40 @@ let mangaContainer: HTMLElement;
 let animeContainer: HTMLElement;
 let gridLimit = $state<number | undefined>(undefined);
 let demoFocused = $state(false);
+let MangaDemoComponent: typeof import("./LandingMangaDemo.svelte").default | null =
+	$state(null);
+let AnimeDemoComponent: typeof import("./LandingAnimeDemo.svelte").default | null =
+	$state(null);
+let mangaDemoImport: Promise<void> | null = null;
+let animeDemoImport: Promise<void> | null = null;
 const COVER_WIDTH = 100;
 const COVER_GAP = 12;
 const dummyCount = 20;
 
+const loadMangaDemo = () => {
+	if (MangaDemoComponent || mangaDemoImport) return;
+
+	mangaDemoImport = import("./LandingMangaDemo.svelte")
+		.then((module) => {
+			MangaDemoComponent = module.default;
+		})
+		.finally(() => {
+			mangaDemoImport = null;
+		});
+};
+
+const loadAnimeDemo = () => {
+	if (AnimeDemoComponent || animeDemoImport) return;
+
+	animeDemoImport = import("./LandingAnimeDemo.svelte")
+		.then((module) => {
+			AnimeDemoComponent = module.default;
+		})
+		.finally(() => {
+			animeDemoImport = null;
+		});
+};
+
 const calculateLimit = () => {
 	const container = mangaContainer || animeContainer;
 
@@ -64,22 +92,25 @@ onMount(() => {
 		document.removeEventListener("keydown", handleKeydown);
 	};
 });
+
+$effect(() => {
+	if (sectionsVisible[0]) loadMangaDemo();
+});
+
+$effect(() => {
+	if (sectionsVisible[1]) loadAnimeDemo();
+});
 </script>
 
 <div class="landing">
   <section class="landing-section" class:visible={sectionsVisible[0]} data-section="0">
     <div class="section-row">
       <div class="section-demo card" bind:this={mangaContainer}>
-        <details class="list" open>
-          <MangaListTemplate
-            due={true}
-            dummy
-            displayUnresolved={false}
-            disableFilter
-            {dummyCount}
-            limit={gridLimit}
-          />
-        </details>
+        {#if MangaDemoComponent}
+          <MangaDemoComponent {dummyCount} limit={gridLimit} />
+        {:else}
+          <div class="demo-placeholder" aria-hidden="true"></div>
+        {/if}
       </div>
 
       <div class="section-info card">
@@ -112,9 +143,11 @@ onMount(() => {
       </div>
 
       <div class="section-demo card" bind:this={animeContainer}>
-        <details class="list" open>
-          <CompletedAnimeList dummy disableFilter {dummyCount} limit={gridLimit} />
-        </details>
+        {#if AnimeDemoComponent}
+          <AnimeDemoComponent {dummyCount} limit={gridLimit} />
+        {:else}
+          <div class="demo-placeholder" aria-hidden="true"></div>
+        {/if}
       </div>
     </div>
   </section>
@@ -257,6 +290,25 @@ onMount(() => {
     min-width: 0;
   }
 
+  .demo-placeholder {
+    min-height: 28rem;
+    border-radius: inherit;
+    background:
+      linear-gradient(
+        110deg,
+        color-mix(in srgb, var(--base01) 85%, transparent) 8%,
+        color-mix(in srgb, var(--base02) 70%, transparent) 18%,
+        color-mix(in srgb, var(--base01) 85%, transparent) 33%
+      ),
+      linear-gradient(
+        180deg,
+        color-mix(in srgb, var(--base01) 88%, transparent),
+        color-mix(in srgb, var(--base00) 96%, transparent)
+      );
+    background-size: 220% 100%, 100% 100%;
+    animation: demoPlaceholderShift 1.8s ease-in-out infinite;
+  }
+
   .section-info {
     flex: 1 1 40%;
     display: flex;
@@ -441,6 +493,16 @@ onMount(() => {
     }
   }
 
+  @keyframes demoPlaceholderShift {
+    0% {
+      background-position: 100% 0, 0 0;
+    }
+
+    100% {
+      background-position: -100% 0, 0 0;
+    }
+  }
+
   @media (max-width: 1000px) {
     .tools-and-demo {
       grid-template-columns: 1fr 1fr;
@@ -463,6 +525,10 @@ onMount(() => {
       flex: 1 1 100%;
     }
 
+    .demo-placeholder {
+      min-height: 20rem;
+    }
+
     .section-info {
       order: -1;
     }
-- 
cgit v1.2.3

