[ReactJS로 영화 웹 만들기 ]10. github page에 내가 만든 웹사이트 업로드하기

이민선(Jasmine)·2022년 12월 21일
0
post-thumbnail

드디어..드디어 CSS 추가한 나만의 영화웹 완성!!
영화웹 이름은
명작 Cinema
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
URL:
https://minsun0714.github.io/reactJS_Nomadcoders_free_course/

삐까뻔쩍한 웹페이지는 아니지만 그래도 제 기능은 해낼 수 있는 (^^ㅋㅋㅋㅋ) 웹페이지를 하나 만들었다.
왕초보여서 Detail 페이지 손보고 CSS 입히고 장장 이틀 넘게 걸림.
이제 github page에 올려보자.

먼저 github에 올릴 수 있도록 명령어를 입력하자.

$ npm i gh-pages

github pages: 내가 html, CSS, Javascript 파일을 올리면 그걸 웹사이트로 만들어서 전세계에 무료로 배포해줌. + 도메인도 겟할 수 있음.

package.json에 있는 script 확인
-> build : 우리 웹사이트의 production ready code를 생성.
production ready: 코드가 압축되고 모든 것이 최적화됨

$ npm run build

build라는 폴더가 생성된다.

파일이 압축되서 요상한 외계어로 가득함.

이제 github pages에 push해보자.
package.json 마지막 부분에 와서
}옆에 ,찍고
아랫줄에
"homepage":"http://(github username).github.io/repo명" 쓰기

설마 자신의 username을 모르는 사람은 없겠지만

$ git config --global user.name

입력하면 자신의 username 확인 가능하다.

그 다음으로는 scripts에 와서 deploy를 만든다. 우리가 방금 설치한 gh-pages를 실행시키고 build라는 directory를 가져감.
deploy하기 전 npm run build를 실행시켜주는 "predeploy"도 추가한다.

"deploy" : "gh-pages -d build",
"predeploy": "npm run build"

다음으로 주소창에
http://(github username).github.io/repo명
을 검색해서 들어가면

띠용?
웹사이트가 업데이트된 걸 보려면 5분 정도 걸린단다..
안되면 어쩌지 ?? ㅋㅋㅋㅋㅋ 노심초사 jam

엥 진짜 안되는 거였어 ㅋㅋㅋㅋㅋㅋ
index.js에 가서 Home의 Route path에 {process.env.PUBLIC_URL}을 추가해주어야 한다.

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Detail from "./routes/Detail";
import Home from "./routes/Home";
function App() {
  return (
    <Router>
      <Routes>
        <Route path={process.env.PUBLIC_URL + "/"} element={<Home />} />
        <Route path={"/movie/:id"} element={<Detail />} />
      </Routes>
    </Router>
  );
}
export default App;


404오류가 뜨면 기다리면 되는 것!이라고 한다!

이제 진짜 기다려보자 ㅋㅋㅋ ^^ (노심초사 반 정도 off)

(10분 후) 웨 안뒈 .. 나 성급한 한국인이야..
(20분 후) um.. 뭔가 이상한데?

(100만년 후 (사실 약 90분 후) 뚝딱뚝딱 우당탕탕 와장창창))
웹페이지 도메인은 레포명을 붙여 만드는데, 해당 레포에 같은 도메인명을 가진 웹페이지를 예전에 만들었어서 자꾸 예전에 만든 페이지가 뜬다.
예전에 만든 페이지를 unpublish site하고 다시 시도했다.(로 나의 90분을 요약하여 설명한다.)

git에 레포에 들어가서
Actions를 클릭하면

workflows를 볼 수 있다.
밑에 있는 pages build and deployment들은 도메인명이 겹치는 페이지 때문에 수많은 뻘짓한 흔적들 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 하 ㅋㅋㅋ

이번에도 또 낚시겠지..


떴다 !!!!!! 떴ㅇ!!!!!!!

URL:
https://minsun0714.github.io/reactJS_Nomadcoders_free_course/


상세 페이지도 아주 잘 뜬다 ^^

이제 떴으니 코드를 기록하자면

index.js

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);

App.js

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Detail from "./routes/Detail";
import Home from "./routes/Home";
function App() {
  return (
    <Router>
      <Routes>
        <Route path={process.env.PUBLIC_URL + "/"} element={<Home />} />
        <Route path={"/movie/:id"} element={<Detail />} />
      </Routes>
    </Router>
  );
}
export default App;

Home.js

import { useEffect, useState } from "react";
import Movie from "../components/Movie";
import styles from "./Home.module.css";

function Home() {
  const [loading, setLoading] = useState(true);
  const [movies, setMovies] = useState([]);

  const getMovies = async () => {
    const json = await (
      await fetch(
        "https://yts.mx/api/v2/list_movies.json?minimum_rating=8.5&sort_by=year"
      )
    ).json();
    setMovies(json.data.movies);
    setLoading(false);
  };
  useEffect(() => {
    getMovies();
  }, []);

  return (
    <div className={styles.bg}>
      <h1 className={styles.banner}>명작 Cinema </h1>
      <h2 className={styles.num}>
        number of 명작s ready for you ({movies.length})
      </h2>
      <div className={styles.grid}>
        {loading ? (
          <h1>Loading...</h1>
        ) : (
          movies.map((movie) => (
            <div>
              <Movie
                key={movie.id}
                id={movie.id}
                coverImg={movie.medium_cover_image}
                title={movie.title_long}
                summary={movie.summary}
                genres={movie.genres}
                year={movie.year}
              />
            </div>
          ))
        )}
      </div>
    </div>
  );
}
export default Home;

Home.module.css

.banner {
  color: rgb(159, 21, 21);
  font-family: Georgia, "Times New Roman", Times, serif;
  text-align: center;
  font-size: 50px;
  margin-top: 0px;
}
.num {
  font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande",
    "Lucida Sans", Arial, sans-serif;
  text-align: center;
  font-size: 12px;
  color: white;
}

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(1fr);
  text-align: center;
}

.bg {
  background-color: black;
}

body {
  margin: 0px;
}

Detail.js

import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Intro from "../components/Intro";
import styles from "./Detail.module.css";

function Detail() {
  const [movie, setMovie] = useState("");
  const [loading, setLoading] = useState(true);
  const { id } = useParams();

  const getMovie = async () => {
    const json = await (
      await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
    ).json();
    setMovie(json.data.movie);
    setLoading(false);
  };
  useEffect(() => {
    getMovie();
  }, []);
  return (
    <div>
      {loading ? (
        <h1>Loading..</h1>
      ) : (
        <Intro
          key={id}
          bgImg={movie.large_cover_image}
          title={movie.title_long}
          rating={movie.rating}
          genre={movie.genres}
          url={movie.url}
        />
      )}
    </div>
  );
}
export default Detail;

Detail.module.css

.full {
  width: 100%;
  height: 100%;
}

Movie.js

import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import styles from "./Movie.module.css";

function Movie({ id, coverImg, title, summary, genres, year }) {
  return (
    <div>
      <Link to={`/movie/${id}`}>
        <img src={coverImg} alt={title} />
      </Link>
      <h2 className={styles.title}>
        <Link
          to={`/movie/${id}`}
          style={{ textDecoration: "none", color: "white" }}
        >
          {title}
        </Link>
      </h2>
      <h3 className={styles.genre}>
        {genres.map((g) =>
          g === genres[genres.length - 1] ? `${g}` : `${g}/`
        )}
      </h3>
      <h3 className={styles.sum}>
        {summary.length > 250
          ? summary.split("").splice(0, 250).join("") + ".."
          : summary}
      </h3>
    </div>
  );
}

Movie.propTypes = {
  id: PropTypes.number.isRequired,
  coverImg: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  summary: PropTypes.string.isRequired,
  genres: PropTypes.arrayOf(PropTypes.string).isRequired,
  year: PropTypes.number.isRequired,
};

export default Movie;

Movie.module.css

.title {
  font-style: oblique;
  font-size: 25px;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
  color: white;
  text-decoration: none;
}

.genre {
  color: white;
  font-size: 12px;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
}

.grid {
  display: grid;
  grid-template-columns: repeat(1, 1fr);
  grid-template-rows: repeat(10, 1fr);
}

.sum {
  margin-left: 40px;
  margin-right: 40px;
  color: gray;
}

.color {
  color: white;
}

.full {
  width: 100%;
  height: 100%;
}

h2 {
  text-decoration: none;
}

Intro.js

import { Link } from "react-router-dom";
import styles from "./Intro.module.css";

function Intro({ title, summary, url, genre, rating, bgImg }) {
  return (
    <div className={styles.color}>
      <img src={bgImg} alt={title} className={styles.full} />
      <h2 className={styles.white}>{title}</h2>

      <h3 className={styles.genre}>
        {genre.map((g) => (g !== genre[genre.length - 1] ? `${g}/` : `${g}`))}
      </h3>
      <h3 className={styles.rat}>평점: {rating}</h3>

      <button style={{ height: 50 }}>
        <a href={url} target='_blank' className={styles.btn}>
          Click and watch '{title}' now!
        </a>
      </button>
      <p> {summary}</p>
    </div>
  );
}
export default Intro;

Intro.module.css

.full {
  width: 100%;
  height: 100%;
}

.color {
  background-color: black;
  text-align: center;
}

.white {
  color: whitesmoke;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
}

.genre {
  color: white;
  font-size: 12px;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
}

.btn {
  color: cornflowerblue;
}

.rat {
  color: dimgray;
}

끝!

홈페이지를 deploy하는 건 처음이라 감회가 새롭다.
나만의 도메인이 만들어졌을 때 짜릿함 ㅠㅠ (+ 헤메임의 끝에 있는 안도감)
이제 노마드코더 유료 강의 듣고 강해져서 돌아오겠음니다.

씨유쑨!

profile
기록에 진심인 개발자 🌿

0개의 댓글