Last active
July 10, 2024 07:29
-
-
Save ShariqAnsari88/09dbadfd81c41b399a30f6eb9f1f9548 to your computer and use it in GitHub Desktop.
movix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useRef } from "react"; | |
import { | |
BsFillArrowLeftCircleFill, | |
BsFillArrowRightCircleFill, | |
} from "react-icons/bs"; | |
import { useNavigate } from "react-router-dom"; | |
import { useSelector } from "react-redux"; | |
import dayjs from "dayjs"; | |
import ContentWrapper from "../contentWrapper/ContentWrapper"; | |
import Img from "../lazyLoadImage/Img"; | |
import PosterFallback from "../../assets/no-poster.png"; | |
import "./style.scss"; | |
// CSS | |
@import "../../mixins.scss"; | |
.carousel { | |
margin-bottom: 50px; | |
.contentWrapper { | |
position: relative; | |
} | |
.carouselTitle { | |
font-size: 24px; | |
color: white; | |
margin-bottom: 20px; | |
font-weight: normal; | |
} | |
.arrow { | |
font-size: 30px; | |
color: black; | |
position: absolute; | |
top: 44%; | |
transform: translateY(-50%); | |
cursor: pointer; | |
opacity: 0.5; | |
z-index: 1; | |
display: none; | |
@include md { | |
display: block; | |
} | |
&:hover { | |
opacity: 0.8; | |
} | |
} | |
.carouselLeftNav { | |
left: 30px; | |
} | |
.carouselRighttNav { | |
right: 30px; | |
} | |
.loadingSkeleton { | |
display: flex; | |
gap: 10px; | |
overflow-y: hidden; | |
margin-right: -20px; | |
margin-left: -20px; | |
padding: 0 20px; | |
@include md { | |
gap: 20px; | |
overflow: hidden; | |
margin: 0; | |
padding: 0; | |
} | |
.skeletonItem { | |
width: 125px; | |
@include md { | |
width: calc(25% - 15px); | |
} | |
@include lg { | |
width: calc(20% - 16px); | |
} | |
flex-shrink: 0; | |
.posterBlock { | |
border-radius: 12px; | |
width: 100%; | |
aspect-ratio: 1 / 1.5; | |
margin-bottom: 30px; | |
} | |
.textBlock { | |
display: flex; | |
flex-direction: column; | |
.title { | |
width: 100%; | |
height: 20px; | |
margin-bottom: 10px; | |
} | |
.date { | |
width: 75%; | |
height: 20px; | |
} | |
} | |
} | |
} | |
.carouselItems { | |
display: flex; | |
gap: 10px; | |
overflow-y: hidden; | |
margin-right: -20px; | |
margin-left: -20px; | |
padding: 0 20px; | |
@include md { | |
gap: 20px; | |
overflow: hidden; | |
margin: 0; | |
padding: 0; | |
} | |
.carouselItem { | |
width: 125px; | |
cursor: pointer; | |
@include md { | |
width: calc(25% - 15px); | |
} | |
@include lg { | |
width: calc(20% - 16px); | |
} | |
flex-shrink: 0; | |
.posterBlock { | |
position: relative; | |
width: 100%; | |
aspect-ratio: 1 / 1.5; | |
background-size: cover; | |
background-position: center; | |
margin-bottom: 30px; | |
display: flex; | |
align-items: flex-end; | |
justify-content: space-between; | |
padding: 10px; | |
.lazy-load-image-background { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
border-radius: 12px; | |
overflow: hidden; | |
img { | |
width: 100%; | |
height: 100%; | |
object-fit: cover; | |
object-position: center; | |
} | |
} | |
.circleRating { | |
width: 40px; | |
height: 40px; | |
position: relative; | |
top: 30px; | |
background-color: white; | |
flex-shrink: 0; | |
@include md { | |
width: 50px; | |
height: 50px; | |
} | |
} | |
.genres { | |
display: none; | |
position: relative; | |
@include md { | |
display: flex; | |
flex-flow: wrap; | |
justify-content: flex-end; | |
} | |
} | |
} | |
.textBlock { | |
color: white; | |
display: flex; | |
flex-direction: column; | |
.title { | |
font-size: 16px; | |
margin-bottom: 10px; | |
line-height: 24px; | |
@include ellipsis(1); | |
@include md { | |
font-size: 20px; | |
} | |
} | |
.date { | |
font-size: 14px; | |
opacity: 0.5; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useSelector } from "react-redux"; | |
import "./style.scss"; | |
import ContentWrapper from "../../../components/contentWrapper/ContentWrapper"; | |
import Img from "../../../components/lazyLoadImage/Img"; | |
import avatar from "../../../assets/avatar.png"; | |
const Cast = ({ data, loading }) => { | |
const { url } = useSelector((state) => state.home); | |
const skeleton = () => { | |
return ( | |
<div className="skItem"> | |
<div className="circle skeleton"></div> | |
<div className="row skeleton"></div> | |
<div className="row2 skeleton"></div> | |
</div> | |
); | |
}; | |
return ( | |
<div className="castSection"> | |
<ContentWrapper> | |
<div className="sectionHeading">Top Cast</div> | |
{!loading ? ( | |
<div className="listItems"> | |
Cast Data.... | |
</div> | |
) : ( | |
<div className="castSkeleton"> | |
{skeleton()} | |
{skeleton()} | |
{skeleton()} | |
{skeleton()} | |
{skeleton()} | |
{skeleton()} | |
</div> | |
)} | |
</ContentWrapper> | |
</div> | |
); | |
}; | |
export default Cast; | |
// CSS | |
@import "../../../mixins.scss"; | |
.castSection { | |
position: relative; | |
margin-bottom: 50px; | |
.sectionHeading { | |
font-size: 24px; | |
color: white; | |
margin-bottom: 25px; | |
} | |
.listItems { | |
display: flex; | |
gap: 20px; | |
overflow-y: hidden; | |
margin-right: -20px; | |
margin-left: -20px; | |
padding: 0 20px; | |
@include md { | |
margin: 0; | |
padding: 0; | |
} | |
.listItem { | |
text-align: center; | |
color: white; | |
.profileImg { | |
width: 125px; | |
height: 125px; | |
border-radius: 50%; | |
overflow: hidden; | |
margin-bottom: 15px; | |
@include md { | |
width: 175px; | |
height: 175px; | |
margin-bottom: 25px; | |
} | |
img { | |
width: 100%; | |
height: 100%; | |
object-fit: cover; | |
object-position: center top; | |
display: block; | |
} | |
} | |
.name { | |
font-size: 14px; | |
line-height: 20px; | |
font-weight: 600; | |
@include md { | |
font-size: 18px; | |
line-height: 24px; | |
} | |
} | |
.character { | |
font-size: 14px; | |
line-height: 20px; | |
opacity: 0.5; | |
@include md { | |
font-size: 16px; | |
line-height: 24px; | |
} | |
} | |
} | |
} | |
.castSkeleton { | |
display: flex; | |
gap: 20px; | |
overflow-y: hidden; | |
margin-right: -20px; | |
margin-left: -20px; | |
padding: 0 20px; | |
@include md { | |
margin: 0; | |
padding: 0; | |
} | |
.skItem { | |
.circle { | |
width: 125px; | |
height: 125px; | |
border-radius: 50%; | |
margin-bottom: 15px; | |
@include md { | |
width: 175px; | |
height: 175px; | |
margin-bottom: 25px; | |
} | |
} | |
.row { | |
width: 100%; | |
height: 20px; | |
border-radius: 10px; | |
margin-bottom: 10px; | |
} | |
.row2 { | |
width: 75%; | |
height: 20px; | |
border-radius: 10px; | |
margin: 0 auto; | |
} | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { CircularProgressbar, buildStyles } from "react-circular-progressbar"; | |
import "react-circular-progressbar/dist/styles.css"; | |
import "./style.scss"; | |
const CircleRating = ({ rating }) => { | |
return ( | |
<div className="circleRating"> | |
<CircularProgressbar | |
value={rating} | |
maxValue={10} | |
text={rating} | |
styles={buildStyles({ | |
pathColor: | |
rating < 5 ? "red" : rating < 7 ? "orange" : "green", | |
})} | |
/> | |
</div> | |
); | |
}; | |
export default CircleRating; | |
// CSS | |
.circleRating { | |
background-color: var(--black); | |
border-radius: 50%; | |
padding: 2px; | |
.CircularProgressbar-text { | |
font-size: 34px; | |
font-weight: 700; | |
fill: var(--black); | |
} | |
.CircularProgressbar-trail { | |
stroke: transparent; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import "./style.scss"; | |
const ContentWrapper = ({ children }) => { | |
return <div className="contentWrapper">{children}</div>; | |
}; | |
export default ContentWrapper; | |
// CSS | |
.contentWrapper { | |
width: 100%; | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 0 20px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Similar | |
import React from "react"; | |
import Carousel from "../../../components/carousel/Carousel"; | |
import useFetch from "../../../hooks/useFetch"; | |
const Similar = ({ mediaType, id }) => { | |
const { data, loading, error } = useFetch(`/${mediaType}/${id}/similar`); | |
const title = mediaType === "tv" ? "Similar TV Shows" : "Similar Movies"; | |
return ( | |
<Carousel | |
title={title} | |
data={data?.results} | |
loading={loading} | |
endpoint={mediaType} | |
/> | |
); | |
}; | |
export default Similar; | |
// Recommendation | |
import React from "react"; | |
import Carousel from "../../../components/carousel/Carousel"; | |
import useFetch from "../../../hooks/useFetch"; | |
const Recommendation = ({ mediaType, id }) => { | |
const { data, loading, error } = useFetch( | |
`/${mediaType}/${id}/recommendations` | |
); | |
return ( | |
<Carousel | |
title="Recommendations" | |
data={data?.results} | |
loading={loading} | |
endpoint={mediaType} | |
/> | |
); | |
}; | |
export default Recommendation; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState, useEffect } from "react"; | |
import { useParams } from "react-router-dom"; | |
import InfiniteScroll from "react-infinite-scroll-component"; | |
import Select from "react-select"; | |
import "./style.scss"; | |
import useFetch from "../../hooks/useFetch"; | |
import { fetchDataFromApi } from "../../utils/api"; | |
import ContentWrapper from "../../components/contentWrapper/ContentWrapper"; | |
import MovieCard from "../../components/movieCard/MovieCard"; | |
import Spinner from "../../components/spinner/Spinner"; | |
let filters = {}; | |
const sortbyData = [ | |
{ value: "popularity.desc", label: "Popularity Descending" }, | |
{ value: "popularity.asc", label: "Popularity Ascending" }, | |
{ value: "vote_average.desc", label: "Rating Descending" }, | |
{ value: "vote_average.asc", label: "Rating Ascending" }, | |
{ | |
value: "primary_release_date.desc", | |
label: "Release Date Descending", | |
}, | |
{ value: "primary_release_date.asc", label: "Release Date Ascending" }, | |
{ value: "original_title.asc", label: "Title (A-Z)" }, | |
]; | |
const Explore = () => { | |
const [data, setData] = useState(null); | |
const [pageNum, setPageNum] = useState(1); | |
const [loading, setLoading] = useState(false); | |
const [genre, setGenre] = useState(null); | |
const [sortby, setSortby] = useState(null); | |
const { mediaType } = useParams(); | |
const { data: genresData } = useFetch(`/genre/${mediaType}/list`); | |
const fetchInitialData = () => { | |
setLoading(true); | |
fetchDataFromApi(`/discover/${mediaType}`, filters).then((res) => { | |
setData(res); | |
setPageNum((prev) => prev + 1); | |
setLoading(false); | |
}); | |
}; | |
const fetchNextPageData = () => { | |
fetchDataFromApi( | |
`/discover/${mediaType}?page=${pageNum}`, | |
filters | |
).then((res) => { | |
if (data?.results) { | |
setData({ | |
...data, | |
results: [...data?.results, ...res.results], | |
}); | |
} else { | |
setData(res); | |
} | |
setPageNum((prev) => prev + 1); | |
}); | |
}; | |
useEffect(() => { | |
filters = {}; | |
setData(null); | |
setPageNum(1); | |
setSortby(null); | |
setGenre(null); | |
fetchInitialData(); | |
}, [mediaType]); | |
const onChange = (selectedItems, action) => { | |
if (action.name === "sortby") { | |
setSortby(selectedItems); | |
if (action.action !== "clear") { | |
filters.sort_by = selectedItems.value; | |
} else { | |
delete filters.sort_by; | |
} | |
} | |
if (action.name === "genres") { | |
setGenre(selectedItems); | |
if (action.action !== "clear") { | |
let genreId = selectedItems.map((g) => g.id); | |
genreId = JSON.stringify(genreId).slice(1, -1); | |
filters.with_genres = genreId; | |
} else { | |
delete filters.with_genres; | |
} | |
} | |
setPageNum(1); | |
fetchInitialData(); | |
}; | |
return ( | |
<div className="explorePage"> | |
<ContentWrapper> | |
<div className="pageHeader"> | |
<div className="pageTitle"> | |
{mediaType === "tv" | |
? "Explore TV Shows" | |
: "Explore Movies"} | |
</div> | |
<div className="filters"> | |
<Select | |
isMulti | |
name="genres" | |
value={genre} | |
closeMenuOnSelect={false} | |
options={genresData?.genres} | |
getOptionLabel={(option) => option.name} | |
getOptionValue={(option) => option.id} | |
onChange={onChange} | |
placeholder="Select genres" | |
className="react-select-container genresDD" | |
classNamePrefix="react-select" | |
/> | |
<Select | |
name="sortby" | |
value={sortby} | |
options={sortbyData} | |
onChange={onChange} | |
isClearable={true} | |
placeholder="Sort by" | |
className="react-select-container sortbyDD" | |
classNamePrefix="react-select" | |
/> | |
</div> | |
</div> | |
{loading && <Spinner initial={true} />} | |
{!loading && ( | |
<> | |
{data?.results?.length > 0 ? ( | |
<InfiniteScroll | |
className="content" | |
dataLength={data?.results?.length || []} | |
next={fetchNextPageData} | |
hasMore={pageNum <= data?.total_pages} | |
loader={<Spinner />} | |
> | |
{data?.results?.map((item, index) => { | |
if (item.media_type === "person") return; | |
return ( | |
<MovieCard | |
key={index} | |
data={item} | |
mediaType={mediaType} | |
/> | |
); | |
})} | |
</InfiniteScroll> | |
) : ( | |
<span className="resultNotFound"> | |
Sorry, Results not found! | |
</span> | |
)} | |
</> | |
)} | |
</ContentWrapper> | |
</div> | |
); | |
}; | |
export default Explore; | |
// CSS | |
@import "../../mixins.scss"; | |
.explorePage { | |
min-height: 700px; | |
padding-top: 100px; | |
.resultNotFound { | |
font-size: 24px; | |
color: var(--black-light); | |
} | |
.pageHeader { | |
display: flex; | |
justify-content: space-between; | |
margin-bottom: 25px; | |
flex-direction: column; | |
@include md { | |
flex-direction: row; | |
} | |
} | |
.pageTitle { | |
font-size: 24px; | |
line-height: 34px; | |
color: white; | |
margin-bottom: 20px; | |
@include md { | |
margin-bottom: 0; | |
} | |
} | |
.filters { | |
display: flex; | |
gap: 10px; | |
flex-direction: column; | |
@include md { | |
flex-direction: row; | |
} | |
.react-select-container { | |
&.genresDD { | |
width: 100%; | |
@include md { | |
max-width: 500px; | |
min-width: 250px; | |
} | |
} | |
&.sortbyDD { | |
width: 100%; | |
flex-shrink: 0; | |
@include md { | |
width: 250px; | |
} | |
} | |
.react-select__control { | |
border: 0; | |
outline: 0; | |
box-shadow: none; | |
background-color: var(--black-light); | |
border-radius: 20px; | |
.react-select__value-container { | |
.react-select__placeholder, | |
.react-select__input-container { | |
color: white; | |
margin: 0 10px; | |
} | |
} | |
.react-select__single-value { | |
color: white; | |
} | |
.react-select__multi-value { | |
background-color: var(--black3); | |
border-radius: 10px; | |
.react-select__multi-value__label { | |
color: white; | |
} | |
.react-select__multi-value__remove { | |
background-color: transparent; | |
color: white; | |
cursor: pointer; | |
&:hover { | |
color: var(--black-lighter); | |
} | |
} | |
} | |
} | |
.react-select__menu { | |
top: 40px; | |
margin: 0; | |
padding: 0; | |
} | |
} | |
} | |
.content { | |
display: flex; | |
flex-flow: row wrap; | |
gap: 10px; | |
margin-bottom: 50px; | |
@include md { | |
gap: 20px; | |
} | |
.movieCard { | |
.posterBlock { | |
margin-bottom: 30px; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState, useEffect } from "react"; | |
import { HiOutlineSearch } from "react-icons/hi"; | |
import { SlMenu } from "react-icons/sl"; | |
import { VscChromeClose } from "react-icons/vsc"; | |
import { useNavigate, useLocation } from "react-router-dom"; | |
import "./style.scss"; | |
import ContentWrapper from "../contentWrapper/ContentWrapper"; | |
import logo from "../../assets/movix-logo.svg"; | |
const Header = () => { | |
const [show, setShow] = useState("top"); | |
const [lastScrollY, setLastScrollY] = useState(0); | |
const [mobileMenu, setMobileMenu] = useState(false); | |
const [query, setQuery] = useState(""); | |
const [showSearch, setShowSearch] = useState(""); | |
const navigate = useNavigate(); | |
const location = useLocation(); | |
return ( | |
<div>Header</div> | |
); | |
}; | |
export default Header; | |
// CSS | |
@import "../../mixins.scss"; | |
.header { | |
position: fixed; | |
transform: translateY(0); | |
width: 100%; | |
height: 60px; | |
z-index: 1; | |
display: flex; | |
align-items: center; | |
transition: all ease 0.5s; | |
z-index: 2; | |
&.top { | |
background: rgba(0, 0, 0, 0.25); | |
backdrop-filter: blur(3.5px); | |
-webkit-backdrop-filter: blur(3.5px); | |
} | |
&.show { | |
background-color: var(--black3); | |
} | |
&.hide { | |
transform: translateY(-60px); | |
} | |
.contentWrapper { | |
display: flex; | |
align-items: center; | |
justify-content: space-between; | |
} | |
.logo { | |
cursor: pointer; | |
img { | |
height: 50px; | |
} | |
} | |
.menuItems { | |
list-style-type: none; | |
display: none; | |
align-items: center; | |
@include md { | |
display: flex; | |
} | |
.menuItem { | |
height: 60px; | |
display: flex; | |
align-items: center; | |
margin: 0 15px; | |
color: white; | |
font-weight: 500; | |
position: relative; | |
&.searchIcon { | |
margin-right: 0; | |
} | |
svg { | |
font-size: 18px; | |
} | |
cursor: pointer; | |
&:hover { | |
color: var(--pink); | |
} | |
} | |
} | |
.mobileMenuItems { | |
display: flex; | |
align-items: center; | |
gap: 20px; | |
@include md { | |
display: none; | |
} | |
svg { | |
font-size: 18px; | |
color: white; | |
} | |
} | |
&.mobileView { | |
background: var(--black3); | |
.menuItems { | |
display: flex; | |
position: absolute; | |
top: 60px; | |
left: 0; | |
background: var(--black3); | |
flex-direction: column; | |
width: 100%; | |
padding: 20px 0; | |
border-top: 1px solid rgba(255, 255, 255, 0.1); | |
animation: mobileMenu 0.3s ease forwards; | |
.menuItem { | |
font-size: 20px; | |
width: 100%; | |
height: auto; | |
padding: 15px 20px; | |
margin: 0; | |
display: flex; | |
flex-direction: column; | |
align-items: flex-start; | |
&:last-child { | |
display: none; | |
} | |
} | |
} | |
} | |
.searchBar { | |
width: 100%; | |
height: 60px; | |
background-color: white; | |
position: absolute; | |
top: 60px; | |
animation: mobileMenu 0.3s ease forwards; | |
.searchInput { | |
display: flex; | |
align-items: center; | |
height: 40px; | |
margin-top: 10px; | |
width: 100%; | |
svg { | |
font-size: 20px; | |
flex-shrink: 0; | |
margin-left: 10px; | |
cursor: pointer; | |
} | |
input { | |
width: 100%; | |
height: 50px; | |
background-color: white; | |
outline: 0; | |
border: 0; | |
border-radius: 30px 0 0 30px; | |
padding: 0 15px; | |
font-size: 14px; | |
@include md { | |
height: 60px; | |
font-size: 20px; | |
padding: 0 30px; | |
} | |
} | |
} | |
} | |
} | |
@keyframes mobileMenu { | |
0% { | |
transform: translateY(-130%); | |
} | |
100% { | |
transform: translateY(0); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { LazyLoadImage } from "react-lazy-load-image-component"; | |
import "react-lazy-load-image-component/src/effects/blur.css"; | |
const Img = ({ src, className }) => { | |
return ( | |
<LazyLoadImage | |
className={className || ""} | |
alt="" | |
effect="blur" | |
src={src} | |
/> | |
); | |
}; | |
export default Img; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:root { | |
font-family: Inter, Avenir, Helvetica, Arial, sans-serif; | |
font-size: 16px; | |
line-height: 1; | |
font-weight: 500; | |
font-synthesis: none; | |
text-rendering: optimizeLegibility; | |
-webkit-font-smoothing: antialiased; | |
-moz-osx-font-smoothing: grayscale; | |
-webkit-text-size-adjust: 100%; | |
--black: #04152d; | |
--black2: #041226; | |
--black3: #020c1b; | |
--black-lighter: #1c4b91; | |
--black-light: #173d77; | |
--pink: #da2f68; | |
--orange: #f89e00; | |
--gradient: linear-gradient(98.37deg, #f89e00 0.99%, #da2f68 100%); | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
background-color: var(--black); | |
} | |
::-webkit-scrollbar { | |
display: none; | |
} | |
.skeleton { | |
position: relative; | |
overflow: hidden; | |
background-color: #0a2955; | |
&::after { | |
position: absolute; | |
top: 0; | |
right: 0; | |
bottom: 0; | |
left: 0; | |
transform: translateX(-100%); | |
background-image: linear-gradient( | |
90deg, | |
rgba(#193763, 0) 0, | |
rgba(#193763, 0.2) 20%, | |
rgba(#193763, 0.5) 60%, | |
rgba(#193763, 0) | |
); | |
animation: shimmer 2s infinite; | |
content: ""; | |
} | |
@keyframes shimmer { | |
100% { | |
transform: translateX(100%); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@mixin sm { | |
@media only screen and (min-width: 640px) { | |
@content; | |
} | |
} | |
@mixin md { | |
@media only screen and (min-width: 768px) { | |
@content; | |
} | |
} | |
@mixin lg { | |
@media only screen and (min-width: 1024px) { | |
@content; | |
} | |
} | |
@mixin xl { | |
@media only screen and (min-width: 1280px) { | |
@content; | |
} | |
} | |
@mixin xxl { | |
@media only screen and (min-width: 1536px) { | |
@content; | |
} | |
} | |
@mixin ellipsis($line: 2) { | |
display: -webkit-box; | |
-webkit-line-clamp: $line; | |
-webkit-box-orient: vertical; | |
overflow: hidden; | |
text-overflow: ellipsis; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import dayjs from "dayjs"; | |
import { useNavigate } from "react-router-dom"; | |
import { useSelector } from "react-redux"; | |
import "./style.scss"; | |
import Img from "../lazyLoadImage/Img"; | |
import CircleRating from "../circleRating/CircleRating"; | |
import Genres from "../genres/Genres"; | |
import PosterFallback from "../../assets/no-poster.png"; | |
const MovieCard = ({ data, fromSearch, mediaType }) => { | |
const { url } = useSelector((state) => state.home); | |
const navigate = useNavigate(); | |
const posterUrl = data.poster_path | |
? url.poster + data.poster_path | |
: PosterFallback; | |
return ( | |
<div | |
className="movieCard" | |
onClick={() => | |
navigate(`/${data.media_type || mediaType}/${data.id}`) | |
} | |
> | |
<div className="posterBlock"> | |
<Img className="posterImg" src={posterUrl} /> | |
{!fromSearch && ( | |
<React.Fragment> | |
<CircleRating rating={data.vote_average.toFixed(1)} /> | |
<Genres data={data.genre_ids.slice(0, 2)} /> | |
</React.Fragment> | |
)} | |
</div> | |
<div className="textBlock"> | |
<span className="title">{data.title || data.name}</span> | |
<span className="date"> | |
{dayjs(data.release_date).format("MMM D, YYYY")} | |
</span> | |
</div> | |
</div> | |
); | |
}; | |
export default MovieCard; | |
// CSS | |
@import "../../mixins.scss"; | |
.movieCard { | |
width: calc(50% - 5px); | |
margin-bottom: 25px; | |
cursor: pointer; | |
flex-shrink: 0; | |
@include md { | |
width: calc(25% - 15px); | |
} | |
@include lg { | |
width: calc(20% - 16px); | |
} | |
.posterBlock { | |
position: relative; | |
width: 100%; | |
aspect-ratio: 1 / 1.5; | |
background-size: cover; | |
background-position: center; | |
margin-bottom: 30px; | |
display: flex; | |
align-items: flex-end; | |
justify-content: space-between; | |
padding: 10px; | |
transition: all ease 0.5s; | |
.lazy-load-image-background { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
border-radius: 12px; | |
overflow: hidden; | |
img { | |
width: 100%; | |
height: 100%; | |
object-fit: cover; | |
object-position: center; | |
} | |
} | |
.circleRating { | |
width: 40px; | |
height: 40px; | |
position: relative; | |
top: 30px; | |
background-color: white; | |
flex-shrink: 0; | |
@include md { | |
width: 50px; | |
height: 50px; | |
} | |
} | |
.genres { | |
display: none; | |
position: relative; | |
@include md { | |
display: flex; | |
flex-flow: wrap; | |
justify-content: flex-end; | |
} | |
} | |
} | |
.textBlock { | |
color: white; | |
display: flex; | |
flex-direction: column; | |
.title { | |
font-size: 16px; | |
margin-bottom: 10px; | |
line-height: 24px; | |
@include ellipsis(1); | |
@include md { | |
font-size: 20px; | |
} | |
} | |
.date { | |
font-size: 14px; | |
opacity: 0.5; | |
} | |
} | |
&:hover { | |
.posterBlock { | |
opacity: 0.5; | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"dependencies": { | |
"@reduxjs/toolkit": "^1.9.1", | |
"axios": "^1.2.2", | |
"dayjs": "^1.11.7", | |
"react": "^18.2.0", | |
"react-circular-progressbar": "^2.1.0", | |
"react-dom": "^18.2.0", | |
"react-icons": "^4.7.1", | |
"react-infinite-scroll-component": "^6.1.0", | |
"react-lazy-load-image-component": "^1.5.6", | |
"react-player": "^2.11.0", | |
"react-redux": "^8.0.5", | |
"react-router-dom": "^6.6.2", | |
"react-select": "^5.7.0", | |
"sass": "^1.57.1" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import "./style.scss"; | |
import ContentWrapper from "../../components/contentWrapper/ContentWrapper"; | |
const PageNotFound = () => { | |
return ( | |
<div className="pageNotFound"> | |
<ContentWrapper> | |
<span className="bigText">404</span> | |
<span className="smallText">Page not found!</span> | |
</ContentWrapper> | |
</div> | |
); | |
}; | |
export default PageNotFound; | |
// CSS | |
.pageNotFound { | |
height: 700px; | |
padding-top: 200px; | |
.contentWrapper { | |
text-align: center; | |
color: var(--black-light); | |
display: flex; | |
flex-direction: column; | |
.bigText { | |
font-size: 150px; | |
font-weight: 700; | |
} | |
.smallText { | |
font-size: 44px; | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const PlayIcon = () => { | |
return ( | |
<svg | |
version="1.1" | |
xmlns="http://www.w3.org/2000/svg" | |
xmlnsXlink="http://www.w3.org/1999/xlink" | |
x="0px" | |
y="0px" | |
width="80px" | |
height="80px" | |
viewBox="0 0 213.7 213.7" | |
enableBackground="new 0 0 213.7 213.7" | |
xmlSpace="preserve" | |
> | |
<polygon | |
className="triangle" | |
fill="none" | |
strokeWidth="7" | |
strokeLinecap="round" | |
strokeLinejoin="round" | |
strokeMiterlimit="10" | |
points="73.5,62.5 148.5,105.8 73.5,149.1 " | |
></polygon> | |
<circle | |
className="circle" | |
fill="none" | |
strokeWidth="7" | |
strokeLinecap="round" | |
strokeLinejoin="round" | |
strokeMiterlimit="10" | |
cx="106.8" | |
cy="106.8" | |
r="103.3" | |
></circle> | |
</svg> | |
); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import "../../mixins.scss"; | |
.searchResultsPage { | |
min-height: 700px; | |
padding-top: 100px; | |
.resultNotFound { | |
font-size: 24px; | |
color: var(--black-light); | |
} | |
.pageTitle { | |
font-size: 24px; | |
line-height: 34px; | |
color: white; | |
margin-bottom: 25px; | |
} | |
.content { | |
display: flex; | |
flex-flow: row wrap; | |
gap: 10px; | |
margin-bottom: 50px; | |
@include md { | |
gap: 20px; | |
} | |
.movieCard { | |
.posterBlock { | |
margin-bottom: 20px; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import "./style.scss"; | |
const Spinner = ({ initial }) => { | |
return ( | |
<div className={`loadingSpinner ${initial ? "initial" : ""}`}> | |
<svg className="spinner" viewBox="0 0 50 50"> | |
<circle | |
className="path" | |
cx="25" | |
cy="25" | |
r="20" | |
fill="none" | |
strokeWidth="5" | |
></circle> | |
</svg> | |
</div> | |
); | |
}; | |
export default Spinner; | |
// CSS | |
.loadingSpinner { | |
width: 100%; | |
height: 150px; | |
position: relative; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
.spinner { | |
animation: rotate 2s linear infinite; | |
z-index: 2; | |
width: 50px; | |
height: 50px; | |
& .path { | |
stroke: hsl(210, 70, 75); | |
stroke-linecap: round; | |
animation: dash 1.5s ease-in-out infinite; | |
} | |
} | |
&.initial { | |
height: 700px; | |
} | |
@keyframes rotate { | |
100% { | |
transform: rotate(360deg); | |
} | |
} | |
@keyframes dash { | |
0% { | |
stroke-dasharray: 1, 150; | |
stroke-dashoffset: 0; | |
} | |
50% { | |
stroke-dasharray: 90, 150; | |
stroke-dashoffset: -35; | |
} | |
100% { | |
stroke-dasharray: 90, 150; | |
stroke-dashoffset: -124; | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.switchingTabs { | |
height: 34px; | |
background-color: white; | |
border-radius: 20px; | |
padding: 2px; | |
.tabItems { | |
display: flex; | |
align-items: center; | |
height: 30px; | |
position: relative; | |
.tabItem { | |
height: 100%; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
width: 100px; | |
color: var(--black); | |
font-size: 14px; | |
position: relative; | |
z-index: 1; | |
cursor: pointer; | |
transition: color ease 0.3s; | |
&.active { | |
color: white; | |
} | |
} | |
.movingBg { | |
height: 30px; | |
width: 100px; | |
border-radius: 15px; | |
background-image: var(--gradient); | |
position: absolute; | |
left: 0; | |
transition: left cubic-bezier(0.88, -0.35, 0.565, 1.35) 0.4s; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useState } from "react"; | |
import { fetchDataFromApi } from "../utils/api"; | |
const useFetch = (url) => { | |
const [data, setData] = useState(null); | |
const [loading, setLoading] = useState(null); | |
const [error, setError] = useState(null); | |
useEffect(() => { | |
setLoading("loading..."); | |
setData(null); | |
setError(null); | |
fetchDataFromApi(url) | |
.then((res) => { | |
setLoading(false); | |
setData(res); | |
}) | |
.catch((err) => { | |
setLoading(false); | |
setError("Something went wrong!"); | |
}); | |
}, [url]); | |
return { data, loading, error }; | |
}; | |
export default useFetch; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import ReactPlayer from "react-player/youtube"; | |
import "./style.scss"; | |
const VideoPopup = ({ show, setShow, videoId, setVideoId }) => { | |
const hidePopup = () => { | |
setShow(false); | |
setVideoId(null); | |
}; | |
return ( | |
<div className={`videoPopup ${show ? "visible" : ""}`}> | |
<div className="opacityLayer" onClick={hidePopup}></div> | |
<div className="videoPlayer"> | |
<span className="closeBtn" onClick={hidePopup}> | |
Close | |
</span> | |
<ReactPlayer | |
url={`https://www.youtube.com/watch?v=${videoId}`} | |
controls | |
width="100%" | |
height="100%" | |
// playing={true} | |
/> | |
</div> | |
</div> | |
); | |
}; | |
export default VideoPopup; | |
// CSS | |
.videoPopup { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
width: 100%; | |
height: 100%; | |
position: fixed; | |
top: 0; | |
left: 0; | |
opacity: 0; | |
visibility: hidden; | |
z-index: 9; | |
.opacityLayer { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: rgba(0, 0, 0, 0.25); | |
backdrop-filter: blur(3.5px); | |
-webkit-backdrop-filter: blur(3.5px); | |
opacity: 0; | |
transition: opacity 400ms; | |
} | |
.videoPlayer { | |
position: relative; | |
width: 800px; | |
aspect-ratio: 16 / 9; | |
background-color: white; | |
transform: scale(0.2); | |
transition: transform 250ms; | |
.closeBtn { | |
position: absolute; | |
top: -20px; | |
right: 0; | |
color: white; | |
cursor: pointer; | |
} | |
} | |
&.visible { | |
opacity: 1; | |
visibility: visible; | |
.opacityLayer { | |
opacity: 1; | |
} | |
.videoPlayer { | |
transform: scale(1); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from "react"; | |
import "./style.scss"; | |
import ContentWrapper from "../../../components/contentWrapper/ContentWrapper"; | |
import { PlayIcon } from "../playIcon"; | |
import VideoPopup from "../../../components/videoPopup/VideoPopup"; | |
import Img from "../../../components/lazyLoadImage/Img"; | |
const VideosSection = ({ data, loading }) => { | |
const [show, setShow] = useState(false); | |
const [videoId, setVideoId] = useState(null); | |
const loadingSkeleton = () => { | |
return ( | |
<div className="skItem"> | |
<div className="thumb skeleton"></div> | |
<div className="row skeleton"></div> | |
<div className="row2 skeleton"></div> | |
</div> | |
); | |
}; | |
return ( | |
<div className="videosSection"> | |
<ContentWrapper> | |
<div className="sectionHeading">Official Videos</div> | |
{!loading ? ( | |
<div className="videos"> | |
Videos data... | |
</div> | |
) : ( | |
<div className="videoSkeleton"> | |
{loadingSkeleton()} | |
{loadingSkeleton()} | |
{loadingSkeleton()} | |
{loadingSkeleton()} | |
</div> | |
)} | |
</ContentWrapper> | |
<VideoPopup | |
show={show} | |
setShow={setShow} | |
videoId={videoId} | |
setVideoId={setVideoId} | |
/> | |
</div> | |
); | |
}; | |
export default VideosSection; | |
// CSS | |
@import "../../../mixins.scss"; | |
.videosSection { | |
position: relative; | |
margin-bottom: 50px; | |
.sectionHeading { | |
font-size: 24px; | |
color: white; | |
margin-bottom: 25px; | |
} | |
.videos { | |
display: flex; | |
gap: 10px; | |
overflow-x: auto; | |
margin-right: -20px; | |
margin-left: -20px; | |
padding: 0 20px; | |
@include md { | |
gap: 20px; | |
margin: 0; | |
padding: 0; | |
} | |
.videoItem { | |
width: 150px; | |
flex-shrink: 0; | |
@include md { | |
width: 25%; | |
} | |
cursor: pointer; | |
.videoThumbnail { | |
margin-bottom: 15px; | |
position: relative; | |
img { | |
width: 100%; | |
display: block; | |
border-radius: 12px; | |
transition: all 0.7s ease-in-out; | |
} | |
svg { | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
width: 50px; | |
height: 50px; | |
} | |
.triangle { | |
stroke-dasharray: 240; | |
stroke-dashoffset: 480; | |
stroke: white; | |
transform: translateY(0); | |
transition: all 0.7s ease-in-out; | |
} | |
.circle { | |
stroke: white; | |
stroke-dasharray: 650; | |
stroke-dashoffset: 1300; | |
transition: all 0.5s ease-in-out; | |
} | |
&:hover { | |
img { | |
opacity: 0.5; | |
} | |
.triangle { | |
stroke-dashoffset: 0; | |
opacity: 1; | |
stroke: var(--pink); | |
animation: trailorPlay 0.7s ease-in-out; | |
} | |
.circle { | |
stroke-dashoffset: 0; | |
stroke: var(--pink); | |
} | |
} | |
} | |
.videoTitle { | |
color: white; | |
font-size: 14px; | |
line-height: 20px; | |
@include md { | |
font-size: 16px; | |
line-height: 24px; | |
} | |
} | |
} | |
} | |
.videoSkeleton { | |
display: flex; | |
gap: 10px; | |
overflow-x: auto; | |
margin-right: -20px; | |
margin-left: -20px; | |
padding: 0 20px; | |
@include md { | |
gap: 20px; | |
margin: 0; | |
padding: 0; | |
} | |
.skItem { | |
width: 150px; | |
flex-shrink: 0; | |
@include md { | |
width: 25%; | |
} | |
.thumb { | |
width: 100%; | |
aspect-ratio: 16 / 9; | |
border-radius: 12px; | |
margin-bottom: 10px; | |
} | |
.row { | |
height: 20px; | |
width: 100%; | |
border-radius: 10px; | |
margin-bottom: 10px; | |
} | |
.row2 { | |
height: 20px; | |
width: 75%; | |
border-radius: 10px; | |
} | |
} | |
} | |
} | |
and bro when is check the url of image from component and paste it in browser is show image size not supported
bro orignal value of image is not supported in my pc what to do now
bro i have a problem in hero banner its show undefined every time
try async thunk
bro mera Api call nhi ho raha hai kesse solve karen
/movie/popular -- ye tmdb me nhi aa raha
https://api.themoviedb.org/3/discover/movie -- ye link aa raha h
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
bro i have a problem in hero banner its show undefined every time