@@ -97,6 +97,28 @@ const posts = (await getCollection("blog")).sort(
9797 gap: 0.25rem;
9898 }
9999 }
100+
101+ ul li {
102+ opacity: 0;
103+ transform: translateY(30px);
104+ }
105+ ul li.visible {
106+ animation: puzzleClick 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
107+ }
108+ @keyframes puzzleClick {
109+ 0% {
110+ opacity: 0;
111+ transform: translateY(30px);
112+ }
113+ 50% {
114+ opacity: 1;
115+ transform: translateY(-8px);
116+ }
117+ 100% {
118+ opacity: 1;
119+ transform: translateY(0);
120+ }
121+ }
100122 </style >
101123 </head >
102124 <body >
@@ -109,7 +131,13 @@ const posts = (await getCollection("blog")).sort(
109131 <li >
110132 <a href = { ` /blog/${post .id }/ ` } >
111133 { post .data .heroImage && (
112- <Image src = { post .data .heroImage } alt = " " class = " thumbnail" />
134+ <Image
135+ src = { post .data .heroImage }
136+ alt = " "
137+ class = " thumbnail"
138+ loading = " lazy"
139+ decoding = " async"
140+ />
113141 )}
114142 <div class = " content" >
115143 <div class = " header-row" >
@@ -128,5 +156,42 @@ const posts = (await getCollection("blog")).sort(
128156 </section >
129157 </main >
130158 <Footer />
159+ <script >
160+ const init = () => {
161+ const observer = new IntersectionObserver(
162+ (entries) => {
163+ const visibleEntries = entries
164+ .filter((entry) => entry.isIntersecting)
165+ .sort(
166+ (a, b) => a.boundingClientRect.top - b.boundingClientRect.top,
167+ );
168+
169+ const delayPerItem = Math.min(
170+ 100,
171+ 300 / Math.max(visibleEntries.length, 1),
172+ );
173+
174+ visibleEntries.forEach((entry, index) => {
175+ const item = entry.target as HTMLElement;
176+ item.style.animationDelay = `${index * delayPerItem}ms`;
177+ item.classList.add("visible");
178+ observer.unobserve(entry.target);
179+ });
180+ },
181+ { rootMargin: "50px", threshold: 0.1 },
182+ );
183+
184+ document
185+ .querySelectorAll("ul li")
186+ .forEach((item) => observer.observe(item));
187+ };
188+
189+ // Run when idle or after 100ms max
190+ if ("requestIdleCallback" in window) {
191+ requestIdleCallback(init, { timeout: 100 });
192+ } else {
193+ setTimeout(init, 0);
194+ }
195+ </script >
131196 </body >
132197</html >
0 commit comments