diff --git a/src/components/ui/spinner.tsx b/src/components/ui/spinner.tsx
new file mode 100644
index 0000000..a70e713
--- /dev/null
+++ b/src/components/ui/spinner.tsx
@@ -0,0 +1,16 @@
+import { Loader2Icon } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
+ return (
+
+ )
+}
+
+export { Spinner }
diff --git a/src/features/home/components/MangaLoadingState.tsx b/src/features/home/components/MangaLoadingState.tsx
new file mode 100644
index 0000000..1167f72
--- /dev/null
+++ b/src/features/home/components/MangaLoadingState.tsx
@@ -0,0 +1,40 @@
+import { Spinner } from "@/components/ui/spinner";
+import { useRef } from "react";
+
+const CHEEKY_MESSAGES = [
+ "Sharpening katanas and downloading manga...",
+ "Searching for the One Piece... and your titles.",
+ "Summoning the Great Sage for faster loading...",
+ "Powering up to Super Saiyan level... please wait.",
+ "Collecting all seven Dragon Balls to fetch data...",
+ "Even Saitama takes a second to load... sometimes.",
+ "Naruto is training, wait for the results...",
+ "Loading... because we don't have a Death Note for bugs.",
+ "Entering the Hidden Leaf Village... of data.",
+ "Waiting for the next chapter... and your results.",
+ "Training in the Hyperbolic Time Chamber for better speed...",
+ "Collecting chakra for the ultimate data retrieval...",
+ "Waiting for the next hiatus to end... oh wait, just loading.",
+ "Reading the manga faster than you can... hold on.",
+ "Asking the Shinigami for the right data...",
+ "Is this a Jojo reference? No, it's just loading.",
+ "Surpassing our limits... Right here! Right now!",
+ "Hunting for the rarest manga volumes in the digital world...",
+ "Dodging spoilers while fetching your manga...",
+ "Preparing the transmutation circle for your results...",
+];
+
+export const MangaLoadingState = () => {
+ const loadingMessage = useRef(
+ CHEEKY_MESSAGES[Math.floor(Math.random() * CHEEKY_MESSAGES.length)],
+ );
+
+ return (
+
+
+
+ {loadingMessage.current}
+
+
+ );
+};
diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx
index 97a586e..7bdd2c6 100644
--- a/src/pages/Home.tsx
+++ b/src/pages/Home.tsx
@@ -3,12 +3,14 @@ import { useEffect, useRef } from "react";
import { useDebounce } from "use-debounce";
import { useGetMangas } from "@/api/generated/catalog/catalog.ts";
import { AuthHeader } from "@/components/AuthHeader.tsx";
+import { Spinner } from "@/components/ui/spinner.tsx";
import { Pagination } from "@/components/Pagination.tsx";
import { ThemeToggle } from "@/components/ThemeToggle.tsx";
import { Input } from "@/components/ui/input.tsx";
import { useUIState } from "@/contexts/UIStateContext.tsx";
import { FilterSidebar } from "@/features/home/components/FilterSidebar.tsx";
import { MangaGrid } from "@/features/home/components/MangaGrid.tsx";
+import { MangaLoadingState } from "@/features/home/components/MangaLoadingState.tsx";
import { SortDropdown } from "@/features/home/components/SortDropdown.tsx";
import { useDynamicPageSize } from "@/hooks/useDynamicPageSize.ts";
@@ -37,7 +39,12 @@ const Home = () => {
const [debouncedSearchText] = useDebounce(searchText, 500);
- const { data: mangasData, queryKey: mangasQueryKey } = useGetMangas({
+ const {
+ data: mangasData,
+ queryKey: mangasQueryKey,
+ isPending,
+ isFetching,
+ } = useGetMangas({
page: currentPage - 1,
size: itemsPerPage,
sort: ["id"],
@@ -75,7 +82,7 @@ const Home = () => {
onShowAdultContentChange={setShowAdultContent}
/>
-
+
-
- {mangasData?.data?.content && mangasData.data.content.length > 0 ? (
+
+ {isPending ? (
+
+ ) : mangasData?.data?.content && mangasData.data.content.length > 0 ? (
<>
{mangasData.data?.totalElements && (
@@ -149,7 +163,7 @@ const Home = () => {
)}
>
) : (
-
+
No manga found matching your filters.