Skip to content
Open
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Netflix clone
# Youtube clone

To run the project
### 1. Clone this project
`git clone https://github.com/ib-sundeep/netflix-react-clone.git`
`git clone https://github.com/siddharthInterviewbit/youtube-react-clone.git`

### 2. Install dependencies of project

Expand Down
23 changes: 4 additions & 19 deletions src/pages/HomePage.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
import React from 'react';

import MediaSlider from "ui/MediaSlider";
import Header from "ui/Header";
import Sidebar from "ui/Sidebar";
import { useState } from "react";


import React, { useState } from 'react';
import Header from 'ui/Header';
import Sidebar from 'ui/Sidebar';

function HomeScreen() {
const [isToggledSidebar, setIsToggledSideBar] = useState(true);

return (
<div>
<Header
onClickMenu={() => setIsToggledSideBar((isToggled) => !isToggled)}
/>
<Header onClickMenu={() => setIsToggledSideBar((isToggled) => !isToggled)}/>
<Sidebar
toggleSidebar={isToggledSidebar}
/>
<MediaSlider
mediaType="tv"
title="Youtube"
path="/discover/tv"
params={{ with_networks: 213 }}
isLarge
/>
</div>
);
}
Expand Down
3 changes: 1 addition & 2 deletions src/styles/_header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,4 @@
.hp-header-right > .r-icon{
margin: auto 0.7rem;
}
}

}
67 changes: 22 additions & 45 deletions src/ui/Header.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//hooks
import {useState} from 'react';
//Material UI icons
import { useState } from "react";

import MenuIcon from "@mui/icons-material/Menu";
import yt_logo from "../assets/youtube-logo.svg"
import ClearIcon from "@mui/icons-material/Clear";
import SearchIcon from "@mui/icons-material/Search";
import KeyboardVoiceIcon from "@mui/icons-material/KeyboardVoice";
Expand All @@ -10,69 +10,46 @@ import AppsIcon from "@mui/icons-material/Apps";
import NotificationsIcon from "@mui/icons-material/Notifications";
import { Avatar } from "@mui/material";

//Images
import yt_logo from "../assets/youtube-logo.svg";


const Header = (props) => {
//style
const iconColor = {
color: "white",
cursor: "pointer"
};
const [searchTerm, setSearchTerm] = useState('');
const searchInputHandler=(e)=>{
setSearchTerm(e.target.value);
}

return (
<div className="hp-header-container">
const [searchTerm, setSearchTerm] = useState('hello world');
const searchInputHandler=(e) => {
setSearchTerm(e.target.value);
}
return(
<div className="hp-header-container hp-header">
<div className="hp-header-left hp-header">
<MenuIcon
<MenuIcon
style={iconColor}
onClick={() => {
props.onClickMenu();
}}
/>
<img className="header__logo" src={yt_logo} alt="youtube-logo" />
<img className="header__logo" src={yt_logo} alt="youtube" />
</div>
<div className="hp-header-middle hp-header">
<div className="hp-header-control hp-header">
<div className="ctrl-input">
<input type="text" placeholder=" Search" value={searchTerm} onChange={searchInputHandler} />
<input type="text" placeholder="search" value={searchTerm} onChange={searchInputHandler}/>
<div className="clear-input-button">
{ searchTerm.length !== 0 && <ClearIcon
style={iconColor}
sx={{ fontSize: 30 }}
onClick ={()=>{setSearchTerm("")}}
/>}
{searchTerm.length !==0 &&<ClearIcon
style={iconColor}
sx={{fontSize: 30}}
onClick= {() => {setSearchTerm('')}}
/>}

</div>
</div>
<button>
<SearchIcon style={iconColor} sx={{ fontSize: 30 }} />
</button>
</div>
<Avatar sx={{ bgcolor: "#121212", width: 35, height: 35 }}>
<KeyboardVoiceIcon />
</Avatar>
</div>
<div className="hp-header-right hp-header">
<div className="r-icon">
<VideoCallIcon style={iconColor} />
</div>
<div className="r-icon">
{" "}
<AppsIcon style={iconColor} />
</div>
<div className="r-icon">
<NotificationsIcon style={iconColor} />
</div>
<div className="r-icon">
<Avatar sx={{ bgcolor: "#4488d1", width: 35, height: 35 }}>S</Avatar>
</div>
</div>

</div>
);
};

export default Header;
)
}
export default Header;
80 changes: 0 additions & 80 deletions src/ui/MediaCard.js
Original file line number Diff line number Diff line change
@@ -1,80 +0,0 @@
import React, { useState } from 'react';
import classNames from 'classnames';

import { generateImageUrl, ImageSizes } from "utils/tmdb";
import TrailerModal from './TrailerModal';
import AccountCircleIcon from '@mui/icons-material/AccountCircle';

function dayDiff(d) {
const date1 = new Date();
const date2 = new Date(d);
const diffTime = Math.abs(date2 - date1);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
const months = date1.getMonth() - date2.getMonth() +
(12 * (date1.getFullYear() - date2.getFullYear()))
const year = Math.ceil(months/12);
console.log(months);
if(diffDays < 31) {
return (diffDays + " days");
} else if(months < 12) {
return months + " months"
} else {
return year+" years"
}
}
function MediaCard({ media, mediaType, isLarge }) {
const [isTrailerOpen, setTrailerOpen] = useState(false);
const iconColor = {
color: "white",
cursor: "pointer",
height: 45,
width: 45,
};
return (
<>
<div
key={media.id}
className="media-card"
onClick={() => setTrailerOpen(true)}
>
<img
className={classNames(
'media-card__poster',
{ 'media-card__poster--large': isLarge },
)}
src={
isLarge
? generateImageUrl(media.poster_path, ImageSizes.poster)
: generateImageUrl(media.backdrop_path, ImageSizes.card)
}
alt={media.original_title}
/>
<div className="media-card__cover">
<div className="media-card__image">
<AccountCircleIcon
style={iconColor}
/>
</div>
<div className="media-card__desc">
<div className="media-card__name">
{media.title || media.name || media.original_name}
</div>
<div className="media-card__description">
{dayDiff(media.first_air_date) + ' ago'}
</div>
</div>
</div>
</div>
{isTrailerOpen && (
<TrailerModal
mediaType={mediaType}
mediaId={media.id}
media={media}
onClose={() => setTrailerOpen(false)}
/>
)}
</>
);
}

export default MediaCard;
35 changes: 0 additions & 35 deletions src/ui/MediaSlider.js
Original file line number Diff line number Diff line change
@@ -1,35 +0,0 @@
import React, { useState, useEffect } from "react";

import MediaCard from "./MediaCard";
import tmdbApi from 'api/tmdb';

function MediaSlider({ mediaType, title, path, params = {}, isLarge }) {
const [items, setItems] = useState([]);

useEffect(() => {
const fetchData = async () => {
const json = await tmdbApi.get(path, params);
setItems(json.results);
};
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);


return (
<div className="media-slider">
<div className="media-slider__cards">
{items.map((media) => (
<MediaCard
isLarge={isLarge}
key={media.id}
media={media}
mediaType={media.media_type || mediaType}
/>
))}
</div>
</div>
);
}

export default MediaSlider;
11 changes: 7 additions & 4 deletions src/ui/Sidebar.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import PrimarySidebar from "./PrimarySidebar";
import SecondarySideBar from "./SecondarySidebar";
import SecondarySidebar from "./SecondarySidebar";

const Sidebar = ({ toggleSidebar }) => {
return toggleSidebar ? <PrimarySidebar /> : <SecondarySideBar />;
const Sidebar = ({toggleSidebar}) => {
console.log(toggleSidebar);
return (
toggleSidebar ? <PrimarySidebar /> : <SecondarySidebar/>
);
};
export default Sidebar;
export default Sidebar;
44 changes: 0 additions & 44 deletions src/ui/TrailerModal.js
Original file line number Diff line number Diff line change
@@ -1,44 +0,0 @@
import tmdbApi from 'api/tmdb';
import React, { useEffect, useState } from 'react';

function TrailerModal({ mediaType, mediaId, onClose }) {
const [videoId, setVideoId] = useState(null);

useEffect(() => {
async function fetchTrailer() {
const json = await tmdbApi.get(`/${mediaType}/${mediaId}/videos`);
const video = json.results.find(o => o.site === 'YouTube');
setVideoId(video?.key);
}

fetchTrailer();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<>
<div className="trailer-modal-backdrop" onClick={onClose} />
<div className="trailer-modal">
{videoId && (
<iframe
width="100%"
height="100%"
src={`https://www.youtube.com/embed/${videoId}`}
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
)}
<button
className="trailer-modal__close"
onClick={onClose}
>
</button>
</div>
</>
);
}

export default TrailerModal;