From 0277da93e58053520c9f14c09014dd55dc52cdac Mon Sep 17 00:00:00 2001 From: ld3zian <42660576+ld3z@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:36:32 -0700 Subject: [PATCH] error improvements --- src/components/LoadingCard.astro | 26 +++++++++++++++++ src/layouts/Layout.astro | 40 ++++++++++++++++++++++++-- src/lib/api.ts | 48 +++++++++++++++++++++----------- src/pages/[lang]/[type].astro | 40 +++++++++++++++++--------- 4 files changed, 122 insertions(+), 32 deletions(-) create mode 100644 src/components/LoadingCard.astro diff --git a/src/components/LoadingCard.astro b/src/components/LoadingCard.astro new file mode 100644 index 0000000..099c6f8 --- /dev/null +++ b/src/components/LoadingCard.astro @@ -0,0 +1,26 @@ +--- +--- +
+
+ +
+
+ +
+
+ +
+
+ {[1, 2, 3].map(() => ( +
+ ))} +
+
+
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 768b716..9d812e1 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -3,20 +3,43 @@ import ThemeToggle from '../components/ThemeToggle.astro'; interface Props { title: string; + description?: string; } -const { title } = Astro.props; +const { + title, + description = "Discover and track your favorite comics with ComicK-RSS" +} = Astro.props; + +const canonicalURL = new URL(Astro.url.pathname, Astro.site ?? 'https://comick-rss.vercel.app').toString(); --- - - + + + {title} + + + + + + + + + + + + + + + + @@ -63,6 +86,7 @@ const { title } = Astro.props; html { font-family: system-ui, sans-serif; + scroll-behavior: smooth; } code { @@ -76,4 +100,14 @@ const { title } = Astro.props; Courier New, monospace; } + + /* Loading animation */ + @keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: .5; } + } + + .animate-pulse { + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + } \ No newline at end of file diff --git a/src/lib/api.ts b/src/lib/api.ts index 3aca5fd..7b6a50b 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -20,12 +20,39 @@ const urlBase = "https://api.comick.fun/chapter"; let genreCache: Genre[] = []; +const RETRY_COUNT = 3; +const RETRY_DELAY = 1000; + +async function fetchWithRetry(url: string, options: RequestInit = {}, retries = RETRY_COUNT): Promise { + try { + const response = await fetch(url, { + ...options, + headers: { + 'Accept': 'application/json', + 'User-Agent': 'Mozilla/5.0 (compatible; ComicReader/1.0)', + ...options.headers, + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return response; + } catch (error) { + if (retries > 0) { + await new Promise(resolve => setTimeout(resolve, RETRY_DELAY)); + return fetchWithRetry(url, options, retries - 1); + } + throw error; + } +} + export async function fetchGenres(): Promise { if (genreCache.length > 0) return genreCache; try { - const response = await fetch('https://api.comick.fun/genre'); - if (!response.ok) throw new Error(`Failed to fetch genres: ${response.status}`); + const response = await fetchWithRetry('https://api.comick.fun/genre'); genreCache = await response.json(); return genreCache; } catch (error) { @@ -40,21 +67,10 @@ export function getGenreNames(genreIds: number[], genres: Genre[]): string[] { .filter(name => name !== ''); } -export async function fetchComics(language: string = 'en', contentType: string = 'sfw'): Promise { +export async function fetchComics(language: string = 'en', contentType: string = 'sfw', page: number = 1): Promise { try { - const apiUrl = `${urlBase}?lang=${language}&page=1&order=new&accept_erotic_content=${contentType === 'nsfw'}`; - - const response = await fetch(apiUrl, { - headers: { - 'Accept': 'application/json', - 'User-Agent': 'Mozilla/5.0 (compatible; ComicReader/1.0)', - }, - }); - - if (!response.ok) { - throw new Error(`API responded with status: ${response.status}`); - } - + const apiUrl = `${urlBase}?lang=${language}&page=${page}&order=new&accept_erotic_content=${contentType === 'nsfw'}`; + const response = await fetchWithRetry(apiUrl); const data = await response.json(); if (!Array.isArray(data)) { diff --git a/src/pages/[lang]/[type].astro b/src/pages/[lang]/[type].astro index 4131c67..cba7108 100644 --- a/src/pages/[lang]/[type].astro +++ b/src/pages/[lang]/[type].astro @@ -1,9 +1,10 @@ --- import Layout from '../../layouts/Layout.astro'; import ComicCard from '../../components/ComicCard.astro'; +import LoadingCard from '../../components/LoadingCard.astro'; import LanguageSelector from '../../components/LanguageSelector.astro'; import RSSLink from '../../components/RSSLink.astro'; -import { fetchComics, isValidLanguage, isValidContentType, fetchGenres } from '../../lib/api'; +import { fetchComics, isValidLanguage, isValidContentType, fetchGenres, getLanguageName } from '../../lib/api'; import type { Comic } from '../../lib/types'; export async function getStaticPaths() { @@ -34,9 +35,12 @@ try { console.error('Failed to fetch comics:', e); error = e instanceof Error ? e.message : 'Failed to fetch comics'; } + +const title = `ComicK - ${getLanguageName(lang!)} ${type!.toUpperCase()}`; +const description = `Latest ${type!.toUpperCase()} comics in ${getLanguageName(lang!)}. Updated regularly with new chapters.`; --- - +

ComicK-RSS @@ -50,20 +54,30 @@ try { {error && (

Error: {error}

+
)} - {comics.length > 0 ? ( -
- {comics.map(comic => ( +
+ {comics.length > 0 ? ( + comics.map(comic => ( - ))} -
- ) : ( -
-

No comics found. Please try a different language or content type.

-

Language: {lang}, Type: {type}

-
- )} + )) + ) : !error ? ( + Array(10).fill(null).map(() => ( + + )) + ) : ( +
+

No comics found. Please try a different language or content type.

+

Language: {getLanguageName(lang!)}, Type: {type!.toUpperCase()}

+
+ )} +

\ No newline at end of file