Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Main onto Filter Feature Branch #14

Merged
merged 15 commits into from
Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"tabWidth": 2,
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"printWidth": 80,
"useTabs": false,
"endOfLine":"auto"
}
30 changes: 7 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,11 @@
# Next.js + Tailwind CSS Example
# NyumatFlix

This example shows how to use [Tailwind CSS](https://tailwindcss.com/) [(v3.2)](https://tailwindcss.com/blog/tailwindcss-v3-2) with Next.js. It follows the steps outlined in the official [Tailwind docs](https://tailwindcss.com/docs/guides/nextjs).
<div>
<a href="https://nyumatflix.herokuapp.com"><img width=500 height=250 src="https://i.ibb.co/jvhnyKz/nyumatflx2-0.png" alt="nyumatflx2-0" border="0"></a>
</div>

## Deploy your own
<h3>Presenting NyumatFlix 2.0. An improved, fully-featured successor to <a href="https://github.com/Nyumat/NyumatFlix">NyumatFlix</a>.</h3>

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) or preview live with [StackBlitz](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-tailwindcss)
<h1></h1>

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss&project-name=with-tailwindcss&repository-name=with-tailwindcss)

## How to use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:

```bash
npx create-next-app --example with-tailwindcss with-tailwindcss-app
```

```bash
yarn create next-app --example with-tailwindcss with-tailwindcss-app
```

```bash
pnpm create next-app --example with-tailwindcss with-tailwindcss-app
```

Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
<h2>(WIP) Coming Soon</h2>
124 changes: 124 additions & 0 deletions components/Body.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { MapGenreMovie, Movie, TvShow } from "../typings";
import Card from "./Card";
import { Chip, Loader } from "@mantine/core";
import { useAutoAnimate } from "@formkit/auto-animate/react";

type Data = {
filter_data: TvShow[] | Movie[];
};

interface BodyProps {
children: React.ReactNode;
filter: string[];
movies?: Movie[];
searchData?: Movie[];
currentState?: string;
filterData?: Data;
isLoaded?: boolean;
filterLoading?: boolean;
}

const Body = ({
children,
filter,
searchData,
currentState,
filterData,
isLoaded,
filterLoading,
}: BodyProps) => {
const [parent] = useAutoAnimate({
duration: 650,
easing: "ease-in-out",
});

const renderChips = () => {
if (filter.length > 1) {
return (
<>
<div>
<div className="flex flex-wrap gap-2 my-4">
{filter[0] === "" && !filter[1] ? (
<Chip color="cyan">All</Chip>
) : (
filter
.filter((genre) => genre !== "")
.map((genre, index) => (
<Chip key={index} color="cyan">
{MapGenreMovie[parseInt(genre)]}
</Chip>
))
)}
</div>
</div>
{filterLoading ? (
<div className="flex justify-center">
<Loader />
</div>
) : null}

{filterData && filterData.filter_data.length > 0 ? (
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{filterData.filter_data.map((movie, index) => (
<div key={index} className="w-full">
<Card key={index} item={movie} />
</div>
))}
</div>
) : (
<h1 className="text-2xl text-center">
No movies found with these filters.
</h1>
)}
{/* {searchData && searchData.length > 0 ? renderSearch() : <Loader />}
*/}
</>
);
}
};

const renderSearch = () => {
if (searchData) {
const renderMessage = () => {
return (
<div className="text-center text-2xl font-bold text-gray-500 pt-4">
No Results Found
</div>
);
};

return (
<>
{isLoaded && searchData.length === 0 ? (
<div className="flex justify-center">{renderMessage()}</div>
) : null}

{!isLoaded ? (
<div className="flex justify-center">
<Loader />
</div>
) : (
<div>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{searchData.map((movie, index) => (
<div key={index} className="w-full">
<Card key={index} item={movie} />
</div>
))}
</div>
</div>
)}
</>
);
}
};
return (
<div ref={parent as React.RefObject<HTMLDivElement>} className="w-full">
{currentState === "search" ? renderSearch() : null}
{currentState === "filter" ? renderChips() : null}
{currentState === "all" ? children : null}
</div>
);
};

export default Body;
21 changes: 14 additions & 7 deletions components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,37 @@ import { Movie, TvShow } from "../typings";
import moment from "moment";

const MovieCard = ({ movie }: { movie: Movie }) => {
if (movie.poster_path === null) return null;
if (moment(movie.release_date).isAfter(moment())) return null;
return (
<div className="bg-shark-900 p-2 shadow-sm rounded-lg h-full">
<div className="flex flex-col items-center">
<div className="relative z-10 hover:scale-105 transition duration-500 ease-in-out">
<Image
className="rounded-lg inset-0 bg-cover bg-center z-0"
src={`https://image.tmdb.org/t/p/w500/${movie.poster_path}`}
src={`https://image.tmdb.org/t/p/w500${movie.poster_path}`}
alt={movie.title}
width={500}
height={550}
/>
</div>
</div>
<div className="mx-2 my-2 flex flex-col justify-between">
<h1 className="text-white text-lg font-bold">{movie.title}</h1>
<p className="text-white text-sm">
{moment(movie.release_date).format("MMMM Do, YYYY")}
</p>
<p className="text-white text-sm">{movie.vote_average}</p>
<div className="mx-2 my-2 flex flex-row justify-between">
<div className="flex flex-col">
<h1 className="text-white text-lg font-bold mr-4">{movie.title}</h1>
<p className="text-white text-sm">
{moment(movie.release_date).format("MMMM Do, YYYY")}
</p>
</div>
<p className="text-white text-sm flex flex-row">{movie.vote_average}</p>
</div>
</div>
);
};

const TvShowCard = ({ tvShow }: { tvShow: TvShow }) => {
if (tvShow.poster_path === null) return null;
if (tvShow.vote_average === 0) return null;
return (
<div className="bg-shark-900 p-2 shadow-sm rounded-lg h-full">
<div className="flex flex-col items-center">
Expand All @@ -54,6 +60,7 @@ const TvShowCard = ({ tvShow }: { tvShow: TvShow }) => {

const Card = ({ item }: { item: any }) => {
if (!item) return null;
if (item.media_type === "person") return null;
return (
<div className="container mx-auto">
{item.name ? <TvShowCard tvShow={item} /> : <MovieCard movie={item} />}
Expand Down
16 changes: 11 additions & 5 deletions components/DownUpTransition.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { motion, AnimatePresence } from 'framer-motion';
import { useRouter } from 'next/router';
import { motion, AnimatePresence } from "framer-motion";
import { useRouter } from "next/router";

interface TransitionProps {
children: React.ReactNode;
Expand Down Expand Up @@ -27,9 +27,15 @@ export default function Transition({ children }: TransitionProps) {
const { asPath } = useRouter();

return (
<div className='effect-1'>
<AnimatePresence initial={false} mode='popLayout'>
<motion.div key={asPath} variants={variants} animate='in' initial='out' exit='out'>
<div className="effect-1">
<AnimatePresence initial={false} mode="popLayout">
<motion.div
key={asPath}
variants={variants}
animate="in"
initial="out"
exit="out"
>
{children}
</motion.div>
</AnimatePresence>
Expand Down
52 changes: 48 additions & 4 deletions components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,40 @@ import {
Burger,
useMantineTheme,
Center,
Loader,
} from "@mantine/core";
import NavigationBar from "./NavigationBar";
import SideBar from "./SideBar";
import FooterMain from "./Footer";
import { LayoutProps } from "../typings";
import Heading from "./Heading";
import PopOutTransition from "./PopOutTransition";
import UpUpTransition from "./UpUpTransition";
import Body from "./Body";
import useFilter from "../hooks/useFilter";
import useCurrentState from "../hooks/useCurrentState";
import useSearch from "../hooks/useSearch";
import useDefaultMovies from "../hooks/useDefaultMovies";
import useLoading from "../hooks/useLoading";

export default function Layout({ children, isPathRoot }: LayoutProps) {
const theme = useMantineTheme();
const [opened, setOpened] = useState(false);
const [filter, setFilter] = useState<string[]>([""]);
const [searchTerm, setSearchTerm] = useState("");

const { filterData, filterLoading, filterError } = useFilter({ filter });
const { searchData, searchLoading, page, totalPages } = useSearch({
search: searchTerm,
});
const { defaultData, defaultLoading, defaultError } = useDefaultMovies(1);

const { currentState } = useCurrentState({ filter, searchTerm });

const isLoaded = useLoading({
filterLoading,
searchLoading,
defaultLoading,
});

return (
<>
Expand Down Expand Up @@ -51,9 +73,18 @@ export default function Layout({ children, isPathRoot }: LayoutProps) {
}
aside={
<MediaQuery smallerThan="sm" styles={{ display: "none" }}>
<Aside p="md" hiddenBreakpoint="sm" width={{ sm: 200, lg: 300 }}>
<Aside
p="md"
hiddenBreakpoint="sm"
width={{ sm: 200, lg: 300 }}
className="overflow-scroll"
>
<Center>
<SideBar />
<SideBar
filter={filter}
setFilter={setFilter}
setSearchTerm={setSearchTerm}
/>
</Center>
</Aside>
</MediaQuery>
Expand Down Expand Up @@ -91,7 +122,20 @@ export default function Layout({ children, isPathRoot }: LayoutProps) {
</Header>
}
>
<PopOutTransition>{children}</PopOutTransition>
<UpUpTransition>
<div>
<Body
filter={filter}
filterData={filterData}
filterLoading={filterLoading}
searchData={searchData}
currentState={currentState}
isLoaded={isLoaded}
>
{children}
</Body>
</div>
</UpUpTransition>
</AppShell>
)}
</>
Expand Down
20 changes: 10 additions & 10 deletions components/PopOutTransition.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { motion, AnimatePresence, useReducedMotion } from 'framer-motion';
import { useRouter } from 'next/router';
import { motion, AnimatePresence, useReducedMotion } from "framer-motion";
import { useRouter } from "next/router";

interface TransitionProps {
children: React.ReactNode;
Expand All @@ -9,15 +9,15 @@ const variants = {
in: {
scale: 0.8,
y: 100,
x: '100%',
x: "100%",
transition: {
duration: 0.4,
},
},
center: {
x: 0,
scale: 0.8,
transformOrigin: 'top',
transformOrigin: "top",
transition: {
duration: 0.4,
},
Expand All @@ -39,7 +39,7 @@ const variants = {
},
out: {
opacity: 0,
x: '-100%',
x: "-100%",
transition: {
duration: 0.4,
delay: 0.5,
Expand All @@ -52,14 +52,14 @@ export default function PopOutTransition({ children }: TransitionProps) {
const shouldReduceMotion = useReducedMotion();

return (
<div className='effect-3'>
<AnimatePresence initial={false} mode='wait'>
<div className="effect-3">
<AnimatePresence initial={false} mode="wait">
<motion.div
key={asPath}
variants={!shouldReduceMotion ? variants : undefined}
initial='in'
animate={['center', 'scaleUp']}
exit={['scaleDown', 'out']}
initial="in"
animate={["center", "scaleUp"]}
exit={["scaleDown", "out"]}
>
{children}
</motion.div>
Expand Down
Loading