feat: enhance MovieList and MovieRow components with display type toggle and additional props for improved flexibility
This commit is contained in:
parent
6bd1b289d7
commit
653380f0fb
|
|
@ -47,6 +47,8 @@ export default async function Home() {
|
||||||
loadMore
|
loadMore
|
||||||
icon={<FaPlay />}
|
icon={<FaPlay />}
|
||||||
colors="blue"
|
colors="blue"
|
||||||
|
showFilters={false}
|
||||||
|
displayType="list"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -57,6 +59,8 @@ export default async function Home() {
|
||||||
loadMore
|
loadMore
|
||||||
icon={<FaCalendar />}
|
icon={<FaCalendar />}
|
||||||
colors="blue"
|
colors="blue"
|
||||||
|
showFilters={false}
|
||||||
|
displayType="list"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -67,6 +71,8 @@ export default async function Home() {
|
||||||
loadMore
|
loadMore
|
||||||
icon={<FaFire />}
|
icon={<FaFire />}
|
||||||
colors="red"
|
colors="red"
|
||||||
|
showFilters={false}
|
||||||
|
displayType="list"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -77,6 +83,8 @@ export default async function Home() {
|
||||||
loadMore
|
loadMore
|
||||||
icon={<FaChartLine />}
|
icon={<FaChartLine />}
|
||||||
colors="green"
|
colors="green"
|
||||||
|
showFilters={false}
|
||||||
|
displayType="list"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { useOutsideClick } from "@/hooks/useOutsideClick";
|
import { useOutsideClick } from "@/hooks/useOutsideClick";
|
||||||
import { FC, useEffect, useRef, useState } from "react";
|
import { FC, ReactNode, useEffect, useRef, useState } from "react";
|
||||||
import { FaFilter } from "react-icons/fa";
|
import { FaFilter } from "react-icons/fa";
|
||||||
import { Button } from "../Button";
|
import { Button } from "../Button";
|
||||||
|
|
||||||
|
|
@ -9,11 +9,17 @@ type Props = {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
}[];
|
}[];
|
||||||
|
icon?: ReactNode;
|
||||||
defaultValue: string;
|
defaultValue: string;
|
||||||
callback?: (value: string) => void;
|
callback?: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Dropdown: FC<Props> = ({ items, defaultValue, callback }) => {
|
export const Dropdown: FC<Props> = ({
|
||||||
|
items,
|
||||||
|
icon,
|
||||||
|
defaultValue,
|
||||||
|
callback,
|
||||||
|
}) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [value, setValue] = useState<string>(defaultValue);
|
const [value, setValue] = useState<string>(defaultValue);
|
||||||
|
|
@ -27,7 +33,7 @@ export const Dropdown: FC<Props> = ({ items, defaultValue, callback }) => {
|
||||||
return (
|
return (
|
||||||
<div ref={ref} className="relative inline-block">
|
<div ref={ref} className="relative inline-block">
|
||||||
<Button theme="glass" size="icon" onClick={() => setIsOpen(!isOpen)}>
|
<Button theme="glass" size="icon" onClick={() => setIsOpen(!isOpen)}>
|
||||||
<FaFilter />
|
{icon || <FaFilter />}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,16 @@ import Link from "next/link";
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { FaCalendar, FaClock, FaStar } from "react-icons/fa";
|
import { FaCalendar, FaClock, FaStar } from "react-icons/fa";
|
||||||
|
|
||||||
export const MovieRow: FC<{ movie: Movie; isUpcoming: boolean }> = ({
|
type Props = {
|
||||||
|
movie: Movie;
|
||||||
|
isUpcoming?: boolean;
|
||||||
|
compact?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MovieRow: FC<Props> = ({
|
||||||
movie,
|
movie,
|
||||||
isUpcoming,
|
isUpcoming = false,
|
||||||
|
compact = false,
|
||||||
}) => {
|
}) => {
|
||||||
const daysSinceRelease = Math.abs(
|
const daysSinceRelease = Math.abs(
|
||||||
Math.floor(
|
Math.floor(
|
||||||
|
|
@ -56,17 +63,19 @@ export const MovieRow: FC<{ movie: Movie; isUpcoming: boolean }> = ({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
{!compact && (
|
||||||
className={`text-xs px-2 py-1 rounded-full font-medium ${
|
<div
|
||||||
isUpcoming
|
className={`text-xs px-2 py-1 rounded-full font-medium ${
|
||||||
? "bg-blue-500/20 text-blue-400"
|
isUpcoming
|
||||||
: "bg-green-500/20 text-green-400"
|
? "bg-blue-500/20 text-blue-400"
|
||||||
}`}
|
: "bg-green-500/20 text-green-400"
|
||||||
>
|
}`}
|
||||||
{isUpcoming
|
>
|
||||||
? `za ${daysSinceRelease} dni`
|
{isUpcoming
|
||||||
: `od ${daysSinceRelease} dni`}
|
? `za ${daysSinceRelease} dni`
|
||||||
</div>
|
: `od ${daysSinceRelease} dni`}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ export const MovieCast: FC<Props> = ({ movieDetails }) => {
|
||||||
{limit < movieDetails.credits.cast.length && (
|
{limit < movieDetails.credits.cast.length && (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<Button
|
<Button
|
||||||
theme="teal"
|
theme="glass"
|
||||||
size="small"
|
size="small"
|
||||||
className="mt-6"
|
className="mt-6"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,14 @@ import { Dropdown } from "@/components/atoms/Dropdown";
|
||||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||||
import { Button } from "@/components/atoms/Button";
|
import { Button } from "@/components/atoms/Button";
|
||||||
import { Label } from "@/components/atoms/Label";
|
import { Label } from "@/components/atoms/Label";
|
||||||
|
import { FaList } from "react-icons/fa";
|
||||||
|
import { MovieRow } from "@/components/atoms/MovieRow";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
heading?: string;
|
heading?: string;
|
||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
colors?: keyof typeof colorsMap;
|
colors?: keyof typeof colorsMap;
|
||||||
|
displayType?: "grid" | "list";
|
||||||
|
|
||||||
overrideMovies?: Movie[];
|
overrideMovies?: Movie[];
|
||||||
|
|
||||||
|
|
@ -44,10 +47,12 @@ export const MovieList: FC<Props> = ({
|
||||||
sort: sortType = "releaseDate",
|
sort: sortType = "releaseDate",
|
||||||
sortDirection = "asc",
|
sortDirection = "asc",
|
||||||
loadMore = false,
|
loadMore = false,
|
||||||
|
displayType = "grid",
|
||||||
}) => {
|
}) => {
|
||||||
const { movies: storeMovies } = useGlobalStore();
|
const { movies: storeMovies } = useGlobalStore();
|
||||||
const movies = overrideMovies || storeMovies;
|
const movies = overrideMovies || storeMovies;
|
||||||
|
|
||||||
|
const [display, setDisplay] = useState<"grid" | "list">(displayType);
|
||||||
const [filter, setFilter] = useState({
|
const [filter, setFilter] = useState({
|
||||||
seen: filterSeenInitial,
|
seen: filterSeenInitial,
|
||||||
favorites: filterFavoritesInitial,
|
favorites: filterFavoritesInitial,
|
||||||
|
|
@ -58,7 +63,7 @@ export const MovieList: FC<Props> = ({
|
||||||
sortType
|
sortType
|
||||||
);
|
);
|
||||||
|
|
||||||
const [loaded, setLoaded] = useState(loadMore ? 4 : movies.length);
|
const [loaded, setLoaded] = useState(loadMore ? 8 : movies.length);
|
||||||
const [parent] = useAutoAnimate();
|
const [parent] = useAutoAnimate();
|
||||||
|
|
||||||
const filteredMovies = movies.filter((movie) => {
|
const filteredMovies = movies.filter((movie) => {
|
||||||
|
|
@ -189,6 +194,15 @@ export const MovieList: FC<Props> = ({
|
||||||
defaultValue={sort}
|
defaultValue={sort}
|
||||||
callback={(value) => setSort(value as "title")}
|
callback={(value) => setSort(value as "title")}
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
theme="glass"
|
||||||
|
size="icon"
|
||||||
|
onClick={() =>
|
||||||
|
setDisplay(display === "grid" ? "list" : "grid")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FaList />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -201,14 +215,22 @@ export const MovieList: FC<Props> = ({
|
||||||
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-y-6 gap-3 sm:gap-6 mt-8 justify-center"
|
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-y-6 gap-3 sm:gap-6 mt-8 justify-center"
|
||||||
ref={parent}
|
ref={parent}
|
||||||
>
|
>
|
||||||
{sortedMovies.map((movie) => (
|
{sortedMovies.map((movie) =>
|
||||||
<MovieCard key={movie.id} layout="aurora" {...movie} />
|
display === "grid" ? (
|
||||||
))}
|
<MovieCard key={movie.id} layout="aurora" {...movie} />
|
||||||
|
) : (
|
||||||
|
<MovieRow key={movie.id} movie={movie} compact />
|
||||||
|
)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{loadMore && filteredMovies.length > loaded && (
|
{loadMore && filteredMovies.length > loaded && (
|
||||||
<div className="flex justify-center mt-10">
|
<div className="flex justify-center mt-10">
|
||||||
<Button theme="teal" onClick={() => setLoaded(movies.length)}>
|
<Button
|
||||||
|
size="small"
|
||||||
|
theme="glass"
|
||||||
|
onClick={() => setLoaded(movies.length)}
|
||||||
|
>
|
||||||
Pokaż więcej
|
Pokaż więcej
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue