From db94d2480d77d2cbac22f3c098fe47becdb5f8b8 Mon Sep 17 00:00:00 2001 From: Rodrigo Verdiani Date: Sun, 5 Apr 2026 19:45:59 -0300 Subject: [PATCH] feat: add loading states to home page --- src/components/ui/spinner.tsx | 16 ++++++++ .../home/components/MangaLoadingState.tsx | 40 +++++++++++++++++++ src/pages/Home.tsx | 30 ++++++++++---- 3 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 src/components/ui/spinner.tsx create mode 100644 src/features/home/components/MangaLoadingState.tsx 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} /> -
+
@@ -86,9 +93,14 @@ const Home = () => {

MangaMochi

-

- {mangasData?.data?.totalElements} titles available -

+
+

+ {mangasData?.data?.totalElements ?? 0} titles available +

+ {isFetching && ( + + )} +
@@ -114,8 +126,10 @@ const Home = () => {
-
- {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.