diff --git a/app/(content)/(gaming)/games/page.tsx b/app/(content)/(gaming)/games/page.tsx index cacec504f4e0851e6f435fb3ff096d95b3d7f7b8..d0f8a42879a6fdafa951c05b3b49fb51144dcfe5 100644 --- a/app/(content)/(gaming)/games/page.tsx +++ b/app/(content)/(gaming)/games/page.tsx @@ -1,22 +1,26 @@ import Sort from "@/components/filter-sort-games"; import { InfiniteScrollGames } from "@/components/infinity-scroll"; +import ScrollToTop from "@/components/scroll-to-top"; import SearchInput from "@/components/search-input"; // renders a list of games infinitely (presumably) export default async function GamesPage() { return ( - <main className="relative lg:gap-10 xl:grid xl:grid-cols-[1fr_240px]"> - <div className="grid"> - <div className="flex flex-col gap-10 items-center w-full"> - <SearchInput className="p-3 lg:w-2/3 2xl:w-1/3" /> + <> + <main className="relative lg:gap-10 xl:grid xl:grid-cols-[1fr_240px]"> + <div className="grid"> + <div className="flex flex-col gap-10 items-center w-full"> + <SearchInput className="p-3 lg:w-2/3 2xl:w-1/3" /> + </div> + <InfiniteScrollGames /> </div> - <InfiniteScrollGames /> - </div> - <div className="hidden xl:block flex-col md:flex"> - <div className="sticky top-0"> + <div className="hidden xl:block flex-col md:flex"> <Sort /> </div> + </main> + <div className="fixed top-6 left-1/2 -ml-7"> + <ScrollToTop /> </div> - </main> + </> ) } \ No newline at end of file diff --git a/components/filter-sort-games.tsx b/components/filter-sort-games.tsx index a229a73fdb5076c1a415d26b9d42d850f0c9ec03..bf38172f75a738a7c708134d497f97188861e4ac 100644 --- a/components/filter-sort-games.tsx +++ b/components/filter-sort-games.tsx @@ -34,13 +34,9 @@ export default function Sort() { .map((param, index) => (index === 0 ? `?${param}` : `&${param}`)) .join(''); - const queryString = `${queryParamString ? `${queryParamString}` : ''}`; + const url = `${pathname}${queryParamString ? `${queryParamString}` : ''}`; - const url = `${pathname}${queryString ? `${queryString}` : ''}`; - - useEffect(() => { - router.push(url); - }, [router, url]); + router.replace(url); function toggleSortOrder() { const newSortOrder = selectedSortOrder === 'desc' ? 'asc' : 'desc'; diff --git a/components/icons.tsx b/components/icons.tsx index ca3cca6a684a943b5bedb3e5fbcd5d6d6ede68d4..e9a8c6b58bd07cfe18ac947bcb6b2c9a53d32257 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -2,6 +2,7 @@ import { AlertTriangle, ArrowDown, ArrowRight, + ArrowUpToLine, BellRing, Check, ChevronLeft, @@ -72,6 +73,7 @@ export const Icons: IconsType = { moon: Moon, // Dark Mode Toggle Nav arrowdown: ArrowDown, // Descending Sort heart: Heart, // Like Button + arrowupline: ArrowUpToLine, // Back to Top Button close: X, spinner: Loader2, chevronLeft: ChevronLeft, diff --git a/components/infinity-scroll.tsx b/components/infinity-scroll.tsx index d59b27ba67b705e043d44d96fe77a4a4fceb8840..179db1d6a0546eb58487d293ffe11dccd41bbe71 100644 --- a/components/infinity-scroll.tsx +++ b/components/infinity-scroll.tsx @@ -49,30 +49,32 @@ export function InfiniteScrollGames() { <Card className="p-6"> {status === 'error' ? - (<span>Error: {(error as Error).message}</span>) + (<span>Uh oh... something went wrong: {(error as Error).message}</span>) : (status === 'success' && ( <InfiniteScroll dataLength={data?.pages.length * 20} next={fetchNextPage} hasMore={hasNextPage ? true : false} - loader={<h4>Loading more...</h4>} + loader={ + <h1 className="text-center pt-6"> + <b>Trying to load more...</b> + </h1> + } endMessage={ - <p style={{ textAlign: 'center' }}> - <b>Yay! You have seen it all</b> - </p> + <h1 className="text-center pt-6"> + <b>Yay! You have seen it all!</b> + </h1> } > - <div className=""> - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8"> - {data.pages.map((page, i) => ( - <Fragment key={i}> - {page.map((game: IGame) => ( - <Game id={game.id} name={game.name} cover={game.cover} key={game.id} /> - ))} - </Fragment> - ))} - </div> + <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8"> + {data.pages.map((page, i) => ( + <Fragment key={i}> + {page.map((game: IGame) => ( + <Game id={game.id} name={game.name} cover={game.cover} key={game.id} /> + ))} + </Fragment> + ))} </div> </InfiniteScroll> ))} diff --git a/components/scroll-to-top.tsx b/components/scroll-to-top.tsx new file mode 100644 index 0000000000000000000000000000000000000000..bd045beee8eb8fe9a4da11f091f3be4c977c8542 --- /dev/null +++ b/components/scroll-to-top.tsx @@ -0,0 +1,37 @@ +"use client" + +import { cn } from "@/lib/utils"; +import { useEffect, useState } from "react"; +import { Icons } from "./icons"; +import { Button } from "./ui/button"; + +export default function ScrollToTop() { + const [isVisible, setIsVisible] = useState(false); + + const toggleVisibility = () => { + if (window.pageYOffset > 300) { + setIsVisible(true); + } else { + setIsVisible(false); + } + }; + + const scrollToTop = () => { + window.scrollTo({ + top: 0, + behavior: "smooth" + }); + }; + + useEffect(() => { + window.addEventListener("scroll", toggleVisibility); + return () => window.removeEventListener("scroll", toggleVisibility); + }, []); + + return ( + <Button size="lg" onClick={scrollToTop} + className={cn(isVisible ? "block" : "hidden", "")}> + <Icons.arrowupline className="h-3 w-3" aria-hidden="true" /> + </Button> + ); +} \ No newline at end of file