Started adding responsiveness
This commit is contained in:
parent
93c6bc7e80
commit
7b2bd29f62
13 changed files with 230 additions and 173 deletions
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
|
||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>React movie viewer</title>
|
||||
</head>
|
||||
|
|
5
public/icon.svg
Normal file
5
public/icon.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-camera-reels-fill" viewBox="0 0 16 16">
|
||||
<path d="M6 3a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
|
||||
<path d="M9 6a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/>
|
||||
<path d="M9 6h.5a2 2 0 0 1 1.983 1.738l3.11-1.382A1 1 0 0 1 16 7.269v7.462a1 1 0 0 1-1.406.913l-3.111-1.382A2 2 0 0 1 9.5 16H2a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h7z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 404 B |
|
@ -4,11 +4,9 @@ import Movie from "pages/Movie"
|
|||
import Actor from "pages/Actor"
|
||||
import Ratings from "pages/Ratings"
|
||||
import styles from "styles/App.module.css"
|
||||
import TopBar from "components/TopBar"
|
||||
|
||||
const App = () => (
|
||||
<div className={styles.App}>
|
||||
<TopBar />
|
||||
<Routes>
|
||||
<Route index element={<Home />} />
|
||||
<Route path="/movie/:movieId" element={<Movie />} />
|
||||
|
|
|
@ -1,15 +1,44 @@
|
|||
import { useEffect, useState } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
import styles from "styles/TopBar.module.css"
|
||||
|
||||
const TopBar = () => (
|
||||
<div className={styles.Container}>
|
||||
<Link to="/">
|
||||
<h1 className={styles.Title}>React Movie Finder</h1>
|
||||
</Link>
|
||||
<Link to="/ratings">
|
||||
<h1>Your ratings</h1>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
const TopBar = ({ search, setSearch, absolute }) => {
|
||||
const [width, setWidth] = useState(window.innerWidth)
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => setWidth(window.innerWidth)
|
||||
|
||||
window.addEventListener("resize", handleResize)
|
||||
|
||||
return () => window.removeEventListener("resize", handleResize)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${styles.Container} ${
|
||||
absolute && width > 1000 ? styles.Absolute : ""
|
||||
} ${setSearch ? styles.HasSearch : ""}`}
|
||||
>
|
||||
<Link to="/">
|
||||
<h1 className={styles.Title}>React Movie Finder</h1>
|
||||
</Link>
|
||||
|
||||
{setSearch && (
|
||||
<input
|
||||
type="text"
|
||||
className={styles.Search}
|
||||
value={search}
|
||||
autoFocus
|
||||
placeholder="Search for movies..."
|
||||
onChange={({ target }) => setSearch(target.value)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Link to="/ratings" className={styles.Ratings}>
|
||||
<h1>Your ratings</h1>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TopBar
|
||||
|
|
|
@ -3,6 +3,7 @@ import config from "config"
|
|||
import styles from "styles/Actor.module.css"
|
||||
import { Link, useParams } from "react-router-dom"
|
||||
import { GENRES } from "../constants"
|
||||
import TopBar from "components/TopBar"
|
||||
|
||||
const Actor = () => {
|
||||
const { actorId } = useParams()
|
||||
|
@ -62,63 +63,70 @@ const Actor = () => {
|
|||
}, [actorId])
|
||||
|
||||
return (
|
||||
<div className={styles.Container}>
|
||||
<hr />
|
||||
<h1 className={styles.Name}>{actor?.name}</h1>
|
||||
<div className={styles.Section}>
|
||||
<h2>Biography</h2>
|
||||
<div className={styles.Description}>
|
||||
{actor?.biography ? (
|
||||
<a
|
||||
href="#"
|
||||
className={styles.Collapse}
|
||||
onClick={() =>
|
||||
setCollapsed((collapsed) => !collapsed)
|
||||
}
|
||||
>
|
||||
<p className={collapsed ? styles.Collapsed : ""}>
|
||||
{actor.biography}
|
||||
</p>
|
||||
<>
|
||||
<TopBar />
|
||||
<div className={styles.Container}>
|
||||
<hr />
|
||||
<h1 className={styles.Name}>{actor?.name}</h1>
|
||||
<div className={styles.Section}>
|
||||
<h2>Biography</h2>
|
||||
<div className={styles.Description}>
|
||||
{actor?.biography ? (
|
||||
<a
|
||||
href="#"
|
||||
className={styles.Collapse}
|
||||
onClick={() =>
|
||||
setCollapsed((collapsed) => !collapsed)
|
||||
}
|
||||
>
|
||||
<p
|
||||
className={
|
||||
collapsed ? styles.Collapsed : ""
|
||||
}
|
||||
>
|
||||
{actor.biography}
|
||||
</p>
|
||||
|
||||
<p className={styles.ReadMore}>
|
||||
{collapsed ? "Read More" : "Read Less"}
|
||||
</p>
|
||||
<p className={styles.ReadMore}>
|
||||
{collapsed ? "Read More" : "Read Less"}
|
||||
</p>
|
||||
|
||||
<p>{collapsed}</p>
|
||||
</a>
|
||||
) : (
|
||||
<p>No biography available.</p>
|
||||
)}
|
||||
<p>{collapsed}</p>
|
||||
</a>
|
||||
) : (
|
||||
<p>No biography available.</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h2>Images</h2>
|
||||
<div className={styles.Images}>
|
||||
{images?.profiles.map((image) => (
|
||||
<img
|
||||
key={image.file_path}
|
||||
className={styles.Image}
|
||||
src={`https://image.tmdb.org/t/p/w300${image.file_path}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h2>Movies</h2>
|
||||
<div className={styles.Credits}>
|
||||
{credits?.map((movie) => (
|
||||
<Link
|
||||
to={`/movie/${movie.id}`}
|
||||
key={movie.id}
|
||||
className={styles.Movie}
|
||||
>
|
||||
<img src={movie.posterUrl} />
|
||||
<span>{movie.title}</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h2>Images</h2>
|
||||
<div className={styles.Images}>
|
||||
{images?.profiles.map((image) => (
|
||||
<img
|
||||
key={image.file_path}
|
||||
className={styles.Image}
|
||||
src={`https://image.tmdb.org/t/p/w300${image.file_path}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h2>Movies</h2>
|
||||
<div className={styles.Credits}>
|
||||
{credits?.map((movie) => (
|
||||
<Link
|
||||
to={`/movie/${movie.id}`}
|
||||
key={movie.id}
|
||||
className={styles.Movie}
|
||||
>
|
||||
<img src={movie.posterUrl} />
|
||||
<span>{movie.title}</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -47,14 +47,7 @@ const Home = () => {
|
|||
|
||||
return (
|
||||
<div className={styles.Container}>
|
||||
<input
|
||||
type="text"
|
||||
className={styles.Search}
|
||||
value={search}
|
||||
autoFocus
|
||||
placeholder="Search for movies..."
|
||||
onChange={({ target }) => setSearch(target.value)}
|
||||
/>
|
||||
<TopBar search={search} setSearch={setSearch} />
|
||||
<div className={styles.CardList}>
|
||||
{movies?.map((movie) => (
|
||||
<Card key={movie.id} movie={movie} />
|
||||
|
|
|
@ -4,6 +4,7 @@ import styles from "styles/Movie.module.css"
|
|||
import config from "config"
|
||||
import useLocalStorage from "hooks/useLocalStorage"
|
||||
import Rate from "components/Rate"
|
||||
import TopBar from "components/TopBar"
|
||||
|
||||
const Movie = () => {
|
||||
const { movieId } = useParams()
|
||||
|
@ -54,77 +55,78 @@ const Movie = () => {
|
|||
run()
|
||||
}, [movieId])
|
||||
|
||||
return movie ? (
|
||||
<div className={styles.Container}>
|
||||
<div
|
||||
className={styles.Top}
|
||||
style={{
|
||||
backgroundImage: `url(${movie.backdropUrl})`,
|
||||
}}
|
||||
>
|
||||
<div className={styles.Summary}>
|
||||
<h2 className={styles.Title}>
|
||||
{movie.title} - {movie.year}
|
||||
</h2>
|
||||
<p>{movie.tagline}</p>
|
||||
<p className={styles.Overview}>{movie.overview}</p>
|
||||
return (
|
||||
<>
|
||||
<TopBar absolute />
|
||||
<div className={styles.Container}>
|
||||
<div
|
||||
className={styles.Top}
|
||||
style={{
|
||||
backgroundImage: `url(${movie?.backdropUrl})`,
|
||||
}}
|
||||
>
|
||||
<div className={styles.Summary}>
|
||||
<h2 className={styles.Title}>
|
||||
{movie?.title} - {movie?.year}
|
||||
</h2>
|
||||
<p>{movie?.tagline}</p>
|
||||
<p className={styles.Overview}>{movie?.overview}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.Bottom}>
|
||||
<div className={styles.Tags}>
|
||||
{movie.genres.map((genre) => (
|
||||
<p key={genre}>{genre}</p>
|
||||
))}
|
||||
<p className={styles.Average}>
|
||||
<span>
|
||||
Average Rating: {movie.averageVote.toFixed(1)}
|
||||
</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" />
|
||||
</svg>
|
||||
</p>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h1 className={styles.Header}>Your Rating</h1>
|
||||
<Rate rating={rating} setRating={setRating} />
|
||||
<br />
|
||||
<Link to="/ratings" className={styles.RatingsLink}>
|
||||
Go to ratings
|
||||
</Link>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h1 className={styles.Header}>Actors</h1>
|
||||
<div className={styles.Actors}>
|
||||
{cast?.map((actor) => (
|
||||
<Link
|
||||
key={actor.id}
|
||||
to={`/actor/${actor.id}`}
|
||||
className={styles.Actor}
|
||||
>
|
||||
{actor.profile_path ? (
|
||||
<img
|
||||
src={`https://image.tmdb.org/t/p/w200${actor.profile_path}`}
|
||||
alt={actor.name}
|
||||
/>
|
||||
) : (
|
||||
<p>Image Unavailable</p>
|
||||
)}
|
||||
|
||||
<h3>{actor.name}</h3>
|
||||
</Link>
|
||||
<div className={styles.Bottom}>
|
||||
<div className={styles.Tags}>
|
||||
{movie?.genres.map((genre) => (
|
||||
<p key={genre}>{genre}</p>
|
||||
))}
|
||||
<p className={styles.Average}>
|
||||
<span>
|
||||
Average Rating: {movie?.averageVote.toFixed(1)}
|
||||
</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" />
|
||||
</svg>
|
||||
</p>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h1 className={styles.Header}>Your Rating</h1>
|
||||
<Rate rating={rating} setRating={setRating} />
|
||||
<br />
|
||||
<Link to="/ratings" className={styles.RatingsLink}>
|
||||
Go to ratings
|
||||
</Link>
|
||||
</div>
|
||||
<div className={styles.Section}>
|
||||
<h1 className={styles.Header}>Actors</h1>
|
||||
<div className={styles.Actors}>
|
||||
{cast?.map((actor) => (
|
||||
<Link
|
||||
key={actor.id}
|
||||
to={`/actor/${actor.id}`}
|
||||
className={styles.Actor}
|
||||
>
|
||||
{actor.profile_path ? (
|
||||
<img
|
||||
src={`https://image.tmdb.org/t/p/w200${actor.profile_path}`}
|
||||
alt={actor.name}
|
||||
/>
|
||||
) : (
|
||||
<p>Image Unavailable</p>
|
||||
)}
|
||||
|
||||
<h3>{actor.name}</h3>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div></div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Card from "components/Card"
|
||||
import TopBar from "components/TopBar"
|
||||
import useLocalStorage from "hooks/useLocalStorage"
|
||||
import styles from "styles/Ratings.module.css"
|
||||
|
||||
|
@ -11,18 +12,21 @@ const Ratings = () => {
|
|||
])
|
||||
|
||||
return (
|
||||
<div className={styles.Container}>
|
||||
<hr />
|
||||
<div className={styles.CardList}>
|
||||
{ratings?.map((movie) => (
|
||||
<Card
|
||||
key={movie.id}
|
||||
movie={movie}
|
||||
setRating={(rating) => setRating(rating, movie)}
|
||||
/>
|
||||
))}
|
||||
<>
|
||||
<TopBar />
|
||||
<div className={styles.Container}>
|
||||
<hr />
|
||||
<div className={styles.CardList}>
|
||||
{ratings?.map((movie) => (
|
||||
<Card
|
||||
key={movie.id}
|
||||
movie={movie}
|
||||
setRating={(rating) => setRating(rating, movie)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
flex-direction: column;
|
||||
padding: 15px;
|
||||
color: white;
|
||||
padding-top: 80px;
|
||||
}
|
||||
.Name {
|
||||
margin-top: 10px;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 1.5em;
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
.CardList {
|
||||
|
@ -15,14 +14,3 @@
|
|||
gap: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.Search {
|
||||
padding: 0.5em;
|
||||
border: 2px solid white;
|
||||
color: white;
|
||||
font: inherit;
|
||||
width: 20em;
|
||||
height: 3em;
|
||||
border-radius: 10px;
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
.Top {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -16,6 +15,7 @@
|
|||
.Summary {
|
||||
background: linear-gradient(#00000035, black);
|
||||
height: 15%;
|
||||
overflow: scroll;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -50,12 +50,15 @@
|
|||
.Tags {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.Tags > * {
|
||||
background-color: var(--primary);
|
||||
padding: 5px 7px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.Average {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
gap: 1.5em;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
padding-top: 90px;
|
||||
}
|
||||
|
||||
.CardList {
|
||||
|
|
|
@ -1,13 +1,42 @@
|
|||
.Container.HasSearch {
|
||||
--cols: 3;
|
||||
}
|
||||
|
||||
.Container {
|
||||
display: flex;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
padding: 10px 20px;
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
grid-template-columns: repeat(var(--cols, 2), 1fr);
|
||||
padding: 0 30px;
|
||||
align-items: center;
|
||||
background: linear-gradient(to bottom, #00000090, #00000000);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.Container h1 {
|
||||
color: white;
|
||||
.Container.Absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.Container a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.Container a::hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.Search {
|
||||
padding: 0.5em;
|
||||
border: 2px solid white;
|
||||
color: white;
|
||||
font: inherit;
|
||||
justify-self: center;
|
||||
width: 20em;
|
||||
height: 3em;
|
||||
border-radius: 10px;
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
|
||||
.Ratings {
|
||||
justify-self: end;
|
||||
}
|
||||
|
|
Reference in a new issue