diff --git a/src/components/ComicCard.astro b/src/components/ComicCard.astro index f7923b0..476afdf 100644 --- a/src/components/ComicCard.astro +++ b/src/components/ComicCard.astro @@ -31,6 +31,8 @@ const isNSFW = comic.md_comics.content_rating === 'erotica'; alt={comic.md_comics.title} inferSize={true} class="w-full h-full object-cover transition-transform duration-500 group-hover:scale-110" + loading="lazy" + decoding="async" /> ) : (
-

+

{comic.md_comics.title}

@@ -219,21 +224,36 @@ const isNSFW = comic.md_comics.content_rating === 'erotica'; timerSpan.textContent = timeString; } + // Add intersection observer for lazy loading + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const timer = entry.target.querySelector('.countdown-timer'); + if (timer) updateTimer(timer); + } + }); + }); + + // Update countdown timer initialization countdownTimers.forEach(timer => { + observer.observe(timer); updateTimer(timer); - // Update every second - setInterval(() => updateTimer(timer), 1000); + setInterval(() => { + if (timer.isConnected) updateTimer(timer); + }, 1000); }); }); function filterComics() { const excludedGenres = new Set(JSON.parse(localStorage.getItem('excluded-genres') || '[]')); - document.querySelectorAll('[data-genres]').forEach(card => { - const cardGenres = JSON.parse((card as HTMLElement).dataset.genres || '[]'); - const shouldHide = cardGenres.some((genreId: number) => excludedGenres.has(genreId)); - - card.classList.toggle('hidden', shouldHide); + // Use requestAnimationFrame for smoother updates + requestAnimationFrame(() => { + document.querySelectorAll('[data-genres]').forEach(card => { + const cardGenres = JSON.parse((card as HTMLElement).dataset.genres || '[]'); + const shouldHide = cardGenres.some((genreId: number) => excludedGenres.has(genreId)); + card.classList.toggle('hidden', shouldHide); + }); }); } diff --git a/src/components/SlugInput.astro b/src/components/SlugInput.astro index 42a3dc0..227615b 100644 --- a/src/components/SlugInput.astro +++ b/src/components/SlugInput.astro @@ -125,8 +125,15 @@ const languages = [ const promises = [...slugs].map(async (slug) => { try { - // Use our API endpoint instead of direct ComicK API call - const response = await fetch(`/api/comic/${encodeURIComponent(slug)}`); + // Add timeout for comic info fetch + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 5000); + + const response = await fetch(`/api/comic/${encodeURIComponent(slug)}`, { + signal: controller.signal + }); + clearTimeout(timeoutId); + if (!response.ok) throw new Error('Comic not found'); const data = await response.json(); @@ -333,6 +340,17 @@ const languages = [ if (slugString) { try { + // Add loading state + generateRSSLink!.innerHTML = ` + + + + + Generating... + + `; + generateRSSLink!.onclick = null; + const response = await fetch('/api/create-feed', { method: 'POST', headers: { @@ -348,9 +366,16 @@ const languages = [ const { feedId } = await response.json(); generateRSSLink!.href = `/rss/${feedId}.xml`; - generateRSSLink!.onclick = null; } catch (error) { console.error('Failed to generate feed:', error); + generateRSSLink!.innerHTML = ` + + + + + Failed to generate feed + + `; } } else { generateRSSLink!.href = '#'; diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 2d703b7..5cd48b4 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -276,5 +276,6 @@ const announcement = { \ No newline at end of file