Lots of changes
This commit is contained in:
parent
7b9f81dd64
commit
c66526241c
16 changed files with 286 additions and 114 deletions
|
@ -5,7 +5,6 @@
|
||||||
"styles/*": ["styles/*"],
|
"styles/*": ["styles/*"],
|
||||||
"components/*": ["components/*"],
|
"components/*": ["components/*"],
|
||||||
"hooks/*": ["hooks/*"],
|
"hooks/*": ["hooks/*"],
|
||||||
"contexts/*": ["contexts/*"],
|
|
||||||
"pages/*": ["pages/*"]
|
"pages/*": ["pages/*"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#root,
|
|
||||||
.App {
|
.App {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
@ -10,7 +10,9 @@ const Card = ({ movie }) => (
|
||||||
className={styles.Image}
|
className={styles.Image}
|
||||||
/>
|
/>
|
||||||
<div className={styles.Bottom}>
|
<div className={styles.Bottom}>
|
||||||
<p className={styles.Title}>{movie.title}</p>
|
<p className={styles.Title}>
|
||||||
|
{movie.title} - {movie.year}
|
||||||
|
</p>
|
||||||
<p className={styles.Average}>
|
<p className={styles.Average}>
|
||||||
{movie.averageVote}{" "}
|
{movie.averageVote}{" "}
|
||||||
<svg
|
<svg
|
||||||
|
@ -23,6 +25,7 @@ const Card = ({ movie }) => (
|
||||||
<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" />
|
<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>
|
</svg>
|
||||||
</p>
|
</p>
|
||||||
|
<p className={styles.Overview}>{movie.overview}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
|
import styles from "styles/TopBar.module.css"
|
||||||
|
|
||||||
const TopBar = ({ search, setSearch }) => (
|
const TopBar = ({ search, setSearch }) => (
|
||||||
<div id="top-bar">
|
<div className={styles.Container}>
|
||||||
<h1>React Movie Finder</h1>
|
<h1 className={styles.Title}>React Movie Finder</h1>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
className={styles.Search}
|
||||||
value={search}
|
value={search}
|
||||||
|
autoFocus
|
||||||
|
placeholder="Search for movies..."
|
||||||
onChange={({ target }) => setSearch(target.value)}
|
onChange={({ target }) => setSearch(target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
21
src/constants.js
Normal file
21
src/constants.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
export const GENRES = [
|
||||||
|
{ id: 28, name: "Action" },
|
||||||
|
{ id: 12, name: "Adventure" },
|
||||||
|
{ id: 16, name: "Animation" },
|
||||||
|
{ id: 35, name: "Comedy" },
|
||||||
|
{ id: 80, name: "Crime" },
|
||||||
|
{ id: 99, name: "Documentary" },
|
||||||
|
{ id: 18, name: "Drama" },
|
||||||
|
{ id: 10751, name: "Family" },
|
||||||
|
{ id: 14, name: "Fantasy" },
|
||||||
|
{ id: 36, name: "History" },
|
||||||
|
{ id: 27, name: "Horror" },
|
||||||
|
{ id: 10402, name: "Music" },
|
||||||
|
{ id: 9648, name: "Mystery" },
|
||||||
|
{ id: 10749, name: "Romance" },
|
||||||
|
{ id: 878, name: "Science Fiction" },
|
||||||
|
{ id: 10770, name: "TV Movie" },
|
||||||
|
{ id: 53, name: "Thriller" },
|
||||||
|
{ id: 10752, name: "War" },
|
||||||
|
{ id: 37, name: "Western" },
|
||||||
|
]
|
|
@ -1,71 +0,0 @@
|
||||||
import { createContext, useContext, useEffect, useState } from "react"
|
|
||||||
import config from "config"
|
|
||||||
|
|
||||||
const MoviesContext = createContext()
|
|
||||||
|
|
||||||
export const useMovies = () => useContext(MoviesContext)
|
|
||||||
|
|
||||||
export const MoviesProvider = ({ children }) => {
|
|
||||||
const [movies, setMovies] = useState([])
|
|
||||||
const [genres, setGenres] = useState({})
|
|
||||||
const [page, setPage] = useState(1)
|
|
||||||
const [search, setSearch] = useState("")
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const run = async () => {
|
|
||||||
const genresResponse = await fetch(
|
|
||||||
`https://api.themoviedb.org/3/genre/movie/list?api_key=${config.apiKey}`
|
|
||||||
)
|
|
||||||
const genresData = await genresResponse.json()
|
|
||||||
genresData.genres.forEach((genre) =>
|
|
||||||
setGenres((current) => {
|
|
||||||
const copy = {}
|
|
||||||
Object.assign(copy, current)
|
|
||||||
copy[genre.id] = genre.name
|
|
||||||
return copy
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
run()
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const run = async () => {
|
|
||||||
const response = await fetch(
|
|
||||||
`https://api.themoviedb.org/3/${
|
|
||||||
search ? "search" : "discover"
|
|
||||||
}/movie?api_key=${
|
|
||||||
config.apiKey
|
|
||||||
}&page=${page}&query=${encodeURIComponent(search)}`
|
|
||||||
)
|
|
||||||
const data = await response.json()
|
|
||||||
setMovies(
|
|
||||||
data.results.map((movie) => ({
|
|
||||||
id: movie.id,
|
|
||||||
overview: movie.overview,
|
|
||||||
adult: movie.adult,
|
|
||||||
posterUrl: `https://image.tmdb.org/t/p/w342/${movie.poster_path}`,
|
|
||||||
backdropUrl: `https://image.tmdb.org/t/p/original/${movie.backdrop_path}`,
|
|
||||||
genres: movie.genre_ids.map((genreId) => genres[genreId]),
|
|
||||||
title: movie.title,
|
|
||||||
releaseDate: movie.release_date,
|
|
||||||
averageVote: movie.vote_average,
|
|
||||||
voteCount: movie.vote_count,
|
|
||||||
popularity: movie.popularity,
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
run()
|
|
||||||
}, [page, genres])
|
|
||||||
|
|
||||||
const nextPage = () => setPage((page) => page + 1)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MoviesContext.Provider
|
|
||||||
value={[movies, page, search, { nextPage, setSearch }]}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</MoviesContext.Provider>
|
|
||||||
)
|
|
||||||
}
|
|
14
src/hooks/useDebounce.jsx
Normal file
14
src/hooks/useDebounce.jsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { useState, useEffect } from "react"
|
||||||
|
|
||||||
|
export default function useDebounce(value, delay = 500) {
|
||||||
|
const [debouncedValue, setDebouncedValue] = useState(value)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
setDebouncedValue(value)
|
||||||
|
}, delay)
|
||||||
|
return () => clearTimeout(timeout)
|
||||||
|
}, [value, delay])
|
||||||
|
|
||||||
|
return debouncedValue
|
||||||
|
}
|
|
@ -10,14 +10,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: var(--secondary);
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
|
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
|
||||||
"Helvetica Neue", sans-serif;
|
"Helvetica Neue", sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
margin: 0;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
background-color: var(--secondary);
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
|
@ -28,3 +26,13 @@ code {
|
||||||
button {
|
button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 97%;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
|
@ -2,15 +2,12 @@ import React from "react"
|
||||||
import ReactDOM from "react-dom/client"
|
import ReactDOM from "react-dom/client"
|
||||||
import App from "./App"
|
import App from "./App"
|
||||||
import "./index.css"
|
import "./index.css"
|
||||||
import { MoviesProvider } from "contexts/MoviesContext"
|
|
||||||
import { BrowserRouter } from "react-router-dom"
|
import { BrowserRouter } from "react-router-dom"
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root")).render(
|
ReactDOM.createRoot(document.getElementById("root")).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<MoviesProvider>
|
<BrowserRouter>
|
||||||
<BrowserRouter>
|
<App />
|
||||||
<App />
|
</BrowserRouter>
|
||||||
</BrowserRouter>
|
|
||||||
</MoviesProvider>
|
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,49 @@
|
||||||
import { useMovies } from "contexts/MoviesContext"
|
|
||||||
import CardList from "components/CardList"
|
import CardList from "components/CardList"
|
||||||
import TopBar from "components/TopBar"
|
import TopBar from "components/TopBar"
|
||||||
|
import useDebounce from "hooks/useDebounce"
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
import styles from "styles/Home.module.css"
|
import styles from "styles/Home.module.css"
|
||||||
|
import config from "config"
|
||||||
|
import { GENRES } from "../constants"
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const [movies, page, search, { nextPage, setSearch }] = useMovies()
|
const [movies, setMovies] = useState([])
|
||||||
|
const [page, setPage] = useState(1)
|
||||||
|
const [search, setSearch] = useState("")
|
||||||
|
const debouncedSearch = useDebounce(search)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const run = async () => {
|
||||||
|
const response = await fetch(
|
||||||
|
`https://api.themoviedb.org/3/${
|
||||||
|
debouncedSearch ? "search" : "discover"
|
||||||
|
}/movie?api_key=${
|
||||||
|
config.apiKey
|
||||||
|
}&page=${page}&query=${encodeURIComponent(debouncedSearch)}`
|
||||||
|
)
|
||||||
|
const data = await response.json()
|
||||||
|
setMovies(
|
||||||
|
data.results.map((movie) => ({
|
||||||
|
id: movie.id,
|
||||||
|
overview: movie.overview,
|
||||||
|
adult: movie.adult,
|
||||||
|
posterUrl: `https://image.tmdb.org/t/p/w342${movie.poster_path}`,
|
||||||
|
backdropUrl: `https://image.tmdb.org/t/p/original${movie.backdrop_path}`,
|
||||||
|
genres: movie.genre_ids.map((genreId) =>
|
||||||
|
GENRES.find((genre) => genre.id == genreId)
|
||||||
|
),
|
||||||
|
title: movie.title,
|
||||||
|
releaseDate: movie.release_date,
|
||||||
|
year: movie.release_date.split("-")[0],
|
||||||
|
averageVote: movie.vote_average,
|
||||||
|
voteCount: movie.vote_count,
|
||||||
|
popularity: movie.popularity,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
run()
|
||||||
|
}, [page, debouncedSearch])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.Container}>
|
<div className={styles.Container}>
|
||||||
|
|
|
@ -1,37 +1,107 @@
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { useParams } from "react-router-dom"
|
import { useParams } from "react-router-dom"
|
||||||
import { useMovies } from "contexts/MoviesContext"
|
import styles from "styles/Movie.module.css"
|
||||||
|
import config from "config"
|
||||||
|
|
||||||
const Movie = () => {
|
const Movie = () => {
|
||||||
const [movie, setMovie] = useState()
|
|
||||||
const [movies] = useMovies()
|
|
||||||
const { movieId } = useParams()
|
const { movieId } = useParams()
|
||||||
|
const [movie, setMovie] = useState()
|
||||||
|
const [cast, setCast] = useState()
|
||||||
|
|
||||||
useEffect(
|
useEffect(() => {
|
||||||
() => setMovie(movies.find((movie) => movie.id === parseInt(movieId))),
|
const run = async () => {
|
||||||
[movieId, movies]
|
const response = await fetch(
|
||||||
)
|
`https://api.themoviedb.org/3/movie/${movieId}?api_key=${config.apiKey}`
|
||||||
|
)
|
||||||
|
const data = await response.json()
|
||||||
|
setMovie({
|
||||||
|
id: data.id,
|
||||||
|
overview: data.overview,
|
||||||
|
adult: data.adult,
|
||||||
|
posterUrl: `https://image.tmdb.org/t/p/w342${data.poster_path}`,
|
||||||
|
backdropUrl: `https://image.tmdb.org/t/p/original${data.backdrop_path}`,
|
||||||
|
genres: data.genres.map((genre) => genre.name),
|
||||||
|
title: data.title,
|
||||||
|
releaseDate: data.release_date,
|
||||||
|
year: data.release_date.split("-")[0],
|
||||||
|
averageVote: data.vote_average,
|
||||||
|
voteCount: data.vote_count,
|
||||||
|
popularity: data.popularity,
|
||||||
|
tagline: data.tagline,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
run()
|
||||||
|
}, [movieId])
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<div className="movie-jumbo">
|
const run = async () => {
|
||||||
<img src={movie?.backdropUrl} alt={movie?.title} className="top" />
|
const response = await fetch(
|
||||||
<div className="bottom">
|
`https://api.themoviedb.org/3/movie/${movieId}/credits?api_key=${config.apiKey}`
|
||||||
<p className="title">{movie?.title}</p>
|
)
|
||||||
<p className="average">
|
const data = await response.json()
|
||||||
{movie?.averageVote}{" "}
|
setCast(data.cast)
|
||||||
<svg
|
}
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
run()
|
||||||
width="16"
|
}, [movieId])
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
return movie ? (
|
||||||
className="bi bi-star-fill"
|
<div className={styles.Container}>
|
||||||
viewBox="0 0 16 16"
|
<div
|
||||||
>
|
className={styles.Top}
|
||||||
<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" />
|
style={{
|
||||||
</svg>
|
backgroundImage: `url(${movie.backdropUrl})`,
|
||||||
</p>
|
}}
|
||||||
|
>
|
||||||
|
<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 className={styles.Bottom}>
|
||||||
|
<div className={styles.Tags}>
|
||||||
|
{movie.genres.map((genre) => (
|
||||||
|
<p>{genre}</p>
|
||||||
|
))}
|
||||||
|
<p className={styles.Average}>
|
||||||
|
{movie.averageVote}
|
||||||
|
<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}></div>
|
||||||
|
<div className={styles.Section}>
|
||||||
|
<h1 className={styles.Header}>Actors</h1>
|
||||||
|
<div className={styles.Actors}>
|
||||||
|
{cast?.map((actor) => (
|
||||||
|
<div key={actor.id}>
|
||||||
|
{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>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div></div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,15 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Overview {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box !important;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.Title,
|
.Title,
|
||||||
.Average {
|
.Average {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
|
@ -2,4 +2,5 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
58
src/styles/Movie.module.css
Normal file
58
src/styles/Movie.module.css
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
.Container {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Top {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Summary {
|
||||||
|
background: linear-gradient(#00000035, black);
|
||||||
|
height: 15%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Bottom {
|
||||||
|
background-color: black;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
padding: 20px 40px;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Section div {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Actors {
|
||||||
|
display: flex;
|
||||||
|
overflow: scroll;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Actors > * {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Tags > * {
|
||||||
|
background-color: var(--primary);
|
||||||
|
padding: 5px 7px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Average {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
21
src/styles/TopBar.module.css
Normal file
21
src/styles/TopBar.module.css
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
.Container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Search {
|
||||||
|
padding: 0.5em;
|
||||||
|
border: 2px solid white;
|
||||||
|
color: white;
|
||||||
|
font: inherit;
|
||||||
|
width: 20em;
|
||||||
|
height: 3em;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Title {
|
||||||
|
color: white;
|
||||||
|
}
|
|
@ -10,7 +10,6 @@ export default defineConfig({
|
||||||
styles: path.resolve(__dirname, "/src/styles"),
|
styles: path.resolve(__dirname, "/src/styles"),
|
||||||
components: path.resolve(__dirname, "/src/components"),
|
components: path.resolve(__dirname, "/src/components"),
|
||||||
hooks: path.resolve(__dirname, "/src/hooks"),
|
hooks: path.resolve(__dirname, "/src/hooks"),
|
||||||
contexts: path.resolve(__dirname, "/src/contexts"),
|
|
||||||
pages: path.resolve(__dirname, "/src/pages"),
|
pages: path.resolve(__dirname, "/src/pages"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Reference in a new issue