토이프로젝트 개인회고
- 2023.03.27 - 2023.03.30 3일동안 조별로 토이프로젝트를 진행했다. 우리조는 개발관련 영상링크들을 공유하고 추천해주는 기능을 가진 웹사이트를 만들기로했다.
페이지 디자인
- ui/ux디자이너 취업준비할때 디자인의 중요성을 알고 있었기때문에 전체적인 페이지를 먼저 디자인했다.3일이라는 시간안에 기능까지 구현해야 했기때문에 먼저 어떤 페이지가 필요한지 파악하고, 어떤 기능을 구현해야하는지 까지 정리한 후, 27일 저녁부터 28일 오전까지 페이지 디자인을 빠르게 완성했다.
메인페이지

상세페이지

모달 팝업창

기능구현
우리조가 구현하려고 했던 기능들은 이렇게 나누어서 각자 맡은 기능을 구현하기로 했다.
- 메인페이지 슬라이드 기능
- 모달 팝업창으로 db에 값저장.
- db에 저장된 값을 다시 불러와 페이지에 표현
- 검색 기능
- 댓글 기능
- 별점 기능
- 페이지네이션
모달 팝업기능 구현하기
- 내가 맡았던 기능은 상세페이지에 추천영상공유 버튼을 누르면 모달 팝업창이 뜨고 input에 값을 입력하면 입력값이 post요청으로 파이썬에 전달되고 파이썬에서 몽고db로 데이터를 저장하는 기능이다.
Html
- 모달 팝업창의 html구성은 모달 전체를 감싸는 div를 만들고 그안에 모달팝업의 구성을 넣었다. form태그를 이용해 사용자에게 전달받은 값을 post요청으로 파이썬으로 넘겨주는 속성을 부여했다.
<div class="modal">
<div class="modal_body">
<div class="modal-wrap">
<h1>추천영상공유</h1>
<button class="modal-close">
<span class="material-symbols-outlined"> close </span>
</button>
<form class="form" action="./app.py" method="post">
<h2>영상제목</h2>
<input
id="video-name"
name="video-name"
placeholder="영상제목을 입력해주세요"
type="text"
/>
<h2>설명</h2>
<input
id="video-desc"
name="video-desc"
placeholder="설명을 입력해주세요"
type="text"
/>
<h2>링크</h2>
<input
id="video-link"
name="video-link"
placeholder="링크를 삽입해주세요"
type="url"
/>
<button type="submit" class="btn-submit">등록하기</button>
</form>
</div>
</div>
</div>
<button class="modal-open">모달열기</button>
Css
- 모달을 감싸고있는 div태그에 position으로 화면중앙에 위치하게 속성을 넣었다 그리고 배경색을 검은색으로 주고 투명도를 줬다.
@import "./reset.css";
.modal {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
background-color: rgba(0, 0, 0, 0.6);
}
.modal_body {
position: absolute;
top: 50%;
left: 50%;
padding: 30px 40px;
text-align: center;
background-color: rgb(255, 255, 255);
border-radius: 10px;
box-shadow: 0 2px 3px 0 rgba(34, 36, 38, 0.15);
transform: translateX(-50%) translateY(-50%);
}
.modal-wrap h1 {
font-size: 32px;
}
.modal-wrap form {
display: flex;
flex-direction: column;
}
.modal-wrap form button {
margin: 0 auto;
margin-top: 50px;
background-color: #7149c6;
color: aliceblue;
padding: 18px 12px;
width: 120px;
border-radius: 10px;
transition: all 0.3s ease-in-out;
cursor: pointer;
font-size: 18px;
}
.modal-wrap form button:hover {
background-color: #3f1a8d;
}
.modal_body h2 {
margin-top: 40px;
font-size: 20px;
text-align: left;
color: #6e6e6e;
}
.modal_body input {
border-radius: 15px;
width: 556px;
height: 70px;
border: none;
background-color: #e2e2e2;
font-size: 16px;
padding-left: 16px;
margin-top: 8px;
color: #1d1d1d;
}
.modal_body input:focus {
outline: 2px solid #7149c6;
}
.modal-close {
background-color: #fff;
border-radius: 50%;
position: absolute;
top: 32px;
right: 40px;
transform: (-50%, -50%);
}
.material-symbols-outlined {
border-radius: 50%;
transition: 0.3s ease-in-out;
cursor: pointer;
padding: 2px;
}
.material-symbols-outlined:hover {
background-color: rgba(0, 0, 0, 0.1);
}
.div::after {
display: block;
position: relative;
content: "";
width: 100%;
height: 1px;
background-color: #000;
}
JS
- 자바스크립트에서는 변수로 각 버튼을 눌렀을때 이벤트가 실행되게 하기 위해 열기와 닫기 버튼을 변수로 선언하고 display: none, block 속성을 사용해 모달팝업이 없어지게하거나 열리게했다.
//영상등록하기 버튼에 .modal-open 클래스 부여하기
const btnModalOpen = document.querySelector(".modal-open");
const modal = document.querySelector(".modal");
const btnModalClose = document.querySelector(".modal-close");
const btnSumit = document.querySelector(".btn-submit");
const body = document.querySelector("body");
const videoNameVal = document.querySelector("#video-name");
const videoDescVal = document.querySelector("#video-desc");
const videoLinkVal = document.querySelector("#video-link");
let boardId = Date.now();
function handleEvent(e) {
e.preventDefault();
const youTubeUrl = videoLinkVal.value.slice(
32,
videoLinkVal.value.length
);
const imgUrl = `https://i1.ytimg.com/vi/${youTubeUrl}/maxresdefault.jpg`;
if (videoLinkVal.value == "") {
alert("url을 입력하세요");
} else if (!(videoLinkVal.value.substring(0, 4) == "http")) {
alert("유효한 url형식이 아닙니다.");
} else {
let formData = new FormData();
formData.append("videoname_give", videoNameVal.value);
formData.append("videodesc_give", videoDescVal.value);
formData.append("videolink_give", videoLinkVal.value);
formData.append("id_give", boardId);
formData.append("url_give", imgUrl);
console.log(imgUrl);
fetch("/modal", {
headers: {
Accept: "application / json",
},
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((data) => {
window.location.reload();
})
.catch((error) => {
console.log(error);
});
}
}
function handleModalClose() {
modal.style.display = "none";
body.style.overflow = "auto";
}
function handleModalOpen() {
modal.style.display = "block";
body.style.overflow = "hidden";
}
btnSumit.addEventListener("click", handleEvent);
btnModalOpen.addEventListener("click", handleModalOpen);
btnModalClose.addEventListener("click", handleModalClose);
유투브 링크에서 썸네일url주소만 추출하여 db에 저장하기
- 가장핵심적인 기능은 유튜브영상 링크를 입력하고 제출했을때 입력된 유튜브 영상주소에서 유튜브 썸네일url주소만 가져와서 상세페이지에 띄워주는 부분이었다
const videoNameVal = document.querySelector("#video-name");
const videoDescVal = document.querySelector("#video-desc");
const videoLinkVal = document.querySelector("#video-link");
let boardId = Date.now();
function handleEvent(e) {
e.preventDefault();
const youTubeUrl = videoLinkVal.value.slice(
32,
videoLinkVal.value.length
);
const imgUrl = `https://i1.ytimg.com/vi/${youTubeUrl}/maxresdefault.jpg`;
등록하기 버튼을 눌렀을때함수 handleEvent가 실행되는 코드를 짰다 여기서 유튜브 링크를 불러오게하려면
맨뒤에있는 링크를 제외한 나머지 주소를 날려야했다.
https://www.youtube.com/watch?v=ZdsdxxBGhdw
const youTubeUrl = videoLinkVal.value.slice(
32,
videoLinkVal.value.length
);
const imgUrl = `https://i1.ytimg.com/vi/${youTubeUrl}/maxresdefault.jpg`;
그래서 유튜브주소에서 공통된 부분인 앞에서 32글자를 날리고 33번째 글자에서 맨뒤글자까지만 가져온 값을 변수로 선언했다
그리고 그 값을
https://i1.ytimg.com/vi/고유주소/이미지크기.jpg
이 url주소에 넣어 imgUrl 변수로 선언하고 값을 db에 저장하는 코드를 만들었다
참고 블로그:https://mkwip.tistory.com/223
실제로 저장된 유튜브 썸네일 url 주소
https://i1.ytimg.com/vi/KF6t61yuPCY/maxresdefault.jpg

Python
- 자바스크립트에서 넘겨준 값을 파이썬으로받아 몽고db에 저장하는 코드이다.
# config.json
import json
with open("config.json", "r", encoding="utf-8") as f:
config = json.load(f)
#pymongo
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient(config["dbUrl"], tlsCAFile=ca)
db = client.dbTest
# flask
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return render_template('modal.html')
@app.route('/modal', methods=['POST'])
def modal_post():
videoname_receive = request.form['videoname_give']
videodesc_receive = request.form['videodesc_give']
videolink_receive = request.form['videolink_give']
board_receive = request.form['id_give']
url_receive = request.form['url_give']
doc = {
'boardId' : board_receive,
'videoname' : videoname_receive,
'videodesc' : videodesc_receive,
'videolink' : videolink_receive,
'url' : url_receive
}
db.value.insert_one(doc)
print(doc)
return jsonify({'msg': '저장완료'})
# flask port
if __name__ == '__main__':
# 5000포트 사용 중이라고 뜨면 포트 번호를 5001로 변경!
app.run('0.0.0.0',port=5000,debug=True)
트러블슈팅
- input에 입력된 값을 변수로 받아오기위해 dom객체를 선택하고뒤에 .value를 사용해 input에 입력된 값을 가져오려 했으나 콘솔에 찍어보니 아무값도 들어오지 않았다.
const videoNameVal = document.querySelector("#video-name").value;
const videoDescVal = document.querySelector("#video-desc").value;
const videoLinkVal = document.querySelector("#video-link").value;
해결방법
- 문제점: 내가 선언한 변수는 변수를 선언한 시점에 입력된 값을 받아오기때문에 input에 아무것도 입력되지 않았을때의 값을 받아온다는 문제점을 파악했다. 그래서 변수를 선언할때의 .value가 아닌 함수안에서 input이 입력됐을때의 값을 받아오는 코드로 수정을 했다. 그래서 변수명.value로 코드를 수정하니 input에 입력된 값을 잘 받아왔다.
if (videoLinkVal.value == "") {
alert("url을 입력하세요");
} else if (!(videoLinkVal.value.substring(0, 4) == "http")) {
alert("유효한 url형식이 아닙니다.");
} else {
let formData = new FormData();
formData.append("videoname_give", videoNameVal.value);
formData.append("videodesc_give", videoDescVal.value);
formData.append("videolink_give", videoLinkVal.value);
formData.append("id_give", boardId);
formData.append("url_give", imgUrl);
console.log(imgUrl);
느낀점: 다른사람과 같이 협업으로 코드를 짜는게 처음이어서 조금 낯설고 어색했지만 너무 재밌고 희귀한 경험이어서 좋았다고 느꼈다. 하지만 깃과 깃허브를 사용하고 다루는게 많이 서툴러서 계속해서 연습해야겠다고 느꼈고, 3일이라는 짧은시간동안 우리 조원분들과 같이 작은 서비스를 만들어보니 웹의 전체적인 흐름에 대해서 아주조금이지만 이해할 수 있어서 정말 좋았다. 그리고 가장 중요하다고 느낀점은 데이터의 흐름이라는 생각이 들었다 데이터가 값으 받아와졌는지 확인하고 어디에서 어디로 흘러가서 db에 저장되는지 같은부분들을 느낄 수 있어서 좋았던 경험이었다.
깃허브주소:DevView 깃허브
토이프로젝트 개인회고
- 2023.03.27 - 2023.03.30 3일동안 조별로 토이프로젝트를 진행했다. 우리조는 개발관련 영상링크들을 공유하고 추천해주는 기능을 가진 웹사이트를 만들기로했다.
페이지 디자인
- ui/ux디자이너 취업준비할때 디자인의 중요성을 알고 있었기때문에 전체적인 페이지를 먼저 디자인했다.3일이라는 시간안에 기능까지 구현해야 했기때문에 먼저 어떤 페이지가 필요한지 파악하고, 어떤 기능을 구현해야하는지 까지 정리한 후, 27일 저녁부터 28일 오전까지 페이지 디자인을 빠르게 완성했다.
메인페이지

상세페이지

모달 팝업창

기능구현
우리조가 구현하려고 했던 기능들은 이렇게 나누어서 각자 맡은 기능을 구현하기로 했다.
- 메인페이지 슬라이드 기능
- 모달 팝업창으로 db에 값저장.
- db에 저장된 값을 다시 불러와 페이지에 표현
- 검색 기능
- 댓글 기능
- 별점 기능
- 페이지네이션
모달 팝업기능 구현하기
- 내가 맡았던 기능은 상세페이지에 추천영상공유 버튼을 누르면 모달 팝업창이 뜨고 input에 값을 입력하면 입력값이 post요청으로 파이썬에 전달되고 파이썬에서 몽고db로 데이터를 저장하는 기능이다.
Html
- 모달 팝업창의 html구성은 모달 전체를 감싸는 div를 만들고 그안에 모달팝업의 구성을 넣었다. form태그를 이용해 사용자에게 전달받은 값을 post요청으로 파이썬으로 넘겨주는 속성을 부여했다.
<div class="modal">
<div class="modal_body">
<div class="modal-wrap">
<h1>추천영상공유</h1>
<button class="modal-close">
<span class="material-symbols-outlined"> close </span>
</button>
<form class="form" action="./app.py" method="post">
<h2>영상제목</h2>
<input
id="video-name"
name="video-name"
placeholder="영상제목을 입력해주세요"
type="text"
/>
<h2>설명</h2>
<input
id="video-desc"
name="video-desc"
placeholder="설명을 입력해주세요"
type="text"
/>
<h2>링크</h2>
<input
id="video-link"
name="video-link"
placeholder="링크를 삽입해주세요"
type="url"
/>
<button type="submit" class="btn-submit">등록하기</button>
</form>
</div>
</div>
</div>
<button class="modal-open">모달열기</button>
Css
- 모달을 감싸고있는 div태그에 position으로 화면중앙에 위치하게 속성을 넣었다 그리고 배경색을 검은색으로 주고 투명도를 줬다.
@import "./reset.css";
.modal {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
background-color: rgba(0, 0, 0, 0.6);
}
.modal_body {
position: absolute;
top: 50%;
left: 50%;
padding: 30px 40px;
text-align: center;
background-color: rgb(255, 255, 255);
border-radius: 10px;
box-shadow: 0 2px 3px 0 rgba(34, 36, 38, 0.15);
transform: translateX(-50%) translateY(-50%);
}
.modal-wrap h1 {
font-size: 32px;
}
.modal-wrap form {
display: flex;
flex-direction: column;
}
.modal-wrap form button {
margin: 0 auto;
margin-top: 50px;
background-color: #7149c6;
color: aliceblue;
padding: 18px 12px;
width: 120px;
border-radius: 10px;
transition: all 0.3s ease-in-out;
cursor: pointer;
font-size: 18px;
}
.modal-wrap form button:hover {
background-color: #3f1a8d;
}
.modal_body h2 {
margin-top: 40px;
font-size: 20px;
text-align: left;
color: #6e6e6e;
}
.modal_body input {
border-radius: 15px;
width: 556px;
height: 70px;
border: none;
background-color: #e2e2e2;
font-size: 16px;
padding-left: 16px;
margin-top: 8px;
color: #1d1d1d;
}
.modal_body input:focus {
outline: 2px solid #7149c6;
}
.modal-close {
background-color: #fff;
border-radius: 50%;
position: absolute;
top: 32px;
right: 40px;
transform: (-50%, -50%);
}
.material-symbols-outlined {
border-radius: 50%;
transition: 0.3s ease-in-out;
cursor: pointer;
padding: 2px;
}
.material-symbols-outlined:hover {
background-color: rgba(0, 0, 0, 0.1);
}
.div::after {
display: block;
position: relative;
content: "";
width: 100%;
height: 1px;
background-color: #000;
}
JS
- 자바스크립트에서는 변수로 각 버튼을 눌렀을때 이벤트가 실행되게 하기 위해 열기와 닫기 버튼을 변수로 선언하고 display: none, block 속성을 사용해 모달팝업이 없어지게하거나 열리게했다.
//영상등록하기 버튼에 .modal-open 클래스 부여하기
const btnModalOpen = document.querySelector(".modal-open");
const modal = document.querySelector(".modal");
const btnModalClose = document.querySelector(".modal-close");
const btnSumit = document.querySelector(".btn-submit");
const body = document.querySelector("body");
const videoNameVal = document.querySelector("#video-name");
const videoDescVal = document.querySelector("#video-desc");
const videoLinkVal = document.querySelector("#video-link");
let boardId = Date.now();
function handleEvent(e) {
e.preventDefault();
const youTubeUrl = videoLinkVal.value.slice(
32,
videoLinkVal.value.length
);
const imgUrl = `https://i1.ytimg.com/vi/${youTubeUrl}/maxresdefault.jpg`;
if (videoLinkVal.value == "") {
alert("url을 입력하세요");
} else if (!(videoLinkVal.value.substring(0, 4) == "http")) {
alert("유효한 url형식이 아닙니다.");
} else {
let formData = new FormData();
formData.append("videoname_give", videoNameVal.value);
formData.append("videodesc_give", videoDescVal.value);
formData.append("videolink_give", videoLinkVal.value);
formData.append("id_give", boardId);
formData.append("url_give", imgUrl);
console.log(imgUrl);
fetch("/modal", {
headers: {
Accept: "application / json",
},
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((data) => {
window.location.reload();
})
.catch((error) => {
console.log(error);
});
}
}
function handleModalClose() {
modal.style.display = "none";
body.style.overflow = "auto";
}
function handleModalOpen() {
modal.style.display = "block";
body.style.overflow = "hidden";
}
btnSumit.addEventListener("click", handleEvent);
btnModalOpen.addEventListener("click", handleModalOpen);
btnModalClose.addEventListener("click", handleModalClose);
유투브 링크에서 썸네일url주소만 추출하여 db에 저장하기
- 가장핵심적인 기능은 유튜브영상 링크를 입력하고 제출했을때 입력된 유튜브 영상주소에서 유튜브 썸네일url주소만 가져와서 상세페이지에 띄워주는 부분이었다
const videoNameVal = document.querySelector("#video-name");
const videoDescVal = document.querySelector("#video-desc");
const videoLinkVal = document.querySelector("#video-link");
let boardId = Date.now();
function handleEvent(e) {
e.preventDefault();
const youTubeUrl = videoLinkVal.value.slice(
32,
videoLinkVal.value.length
);
const imgUrl = `https://i1.ytimg.com/vi/${youTubeUrl}/maxresdefault.jpg`;
등록하기 버튼을 눌렀을때함수 handleEvent가 실행되는 코드를 짰다 여기서 유튜브 링크를 불러오게하려면
맨뒤에있는 링크를 제외한 나머지 주소를 날려야했다.
https://www.youtube.com/watch?v=ZdsdxxBGhdw
const youTubeUrl = videoLinkVal.value.slice(
32,
videoLinkVal.value.length
);
const imgUrl = `https://i1.ytimg.com/vi/${youTubeUrl}/maxresdefault.jpg`;
그래서 유튜브주소에서 공통된 부분인 앞에서 32글자를 날리고 33번째 글자에서 맨뒤글자까지만 가져온 값을 변수로 선언했다
그리고 그 값을
https://i1.ytimg.com/vi/고유주소/이미지크기.jpg
이 url주소에 넣어 imgUrl 변수로 선언하고 값을 db에 저장하는 코드를 만들었다
참고 블로그:https://mkwip.tistory.com/223
실제로 저장된 유튜브 썸네일 url 주소
https://i1.ytimg.com/vi/KF6t61yuPCY/maxresdefault.jpg

Python
- 자바스크립트에서 넘겨준 값을 파이썬으로받아 몽고db에 저장하는 코드이다.
# config.json
import json
with open("config.json", "r", encoding="utf-8") as f:
config = json.load(f)
#pymongo
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient(config["dbUrl"], tlsCAFile=ca)
db = client.dbTest
# flask
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return render_template('modal.html')
@app.route('/modal', methods=['POST'])
def modal_post():
videoname_receive = request.form['videoname_give']
videodesc_receive = request.form['videodesc_give']
videolink_receive = request.form['videolink_give']
board_receive = request.form['id_give']
url_receive = request.form['url_give']
doc = {
'boardId' : board_receive,
'videoname' : videoname_receive,
'videodesc' : videodesc_receive,
'videolink' : videolink_receive,
'url' : url_receive
}
db.value.insert_one(doc)
print(doc)
return jsonify({'msg': '저장완료'})
# flask port
if __name__ == '__main__':
# 5000포트 사용 중이라고 뜨면 포트 번호를 5001로 변경!
app.run('0.0.0.0',port=5000,debug=True)
트러블슈팅
- input에 입력된 값을 변수로 받아오기위해 dom객체를 선택하고뒤에 .value를 사용해 input에 입력된 값을 가져오려 했으나 콘솔에 찍어보니 아무값도 들어오지 않았다.
const videoNameVal = document.querySelector("#video-name").value;
const videoDescVal = document.querySelector("#video-desc").value;
const videoLinkVal = document.querySelector("#video-link").value;
해결방법
- 문제점: 내가 선언한 변수는 변수를 선언한 시점에 입력된 값을 받아오기때문에 input에 아무것도 입력되지 않았을때의 값을 받아온다는 문제점을 파악했다. 그래서 변수를 선언할때의 .value가 아닌 함수안에서 input이 입력됐을때의 값을 받아오는 코드로 수정을 했다. 그래서 변수명.value로 코드를 수정하니 input에 입력된 값을 잘 받아왔다.
if (videoLinkVal.value == "") {
alert("url을 입력하세요");
} else if (!(videoLinkVal.value.substring(0, 4) == "http")) {
alert("유효한 url형식이 아닙니다.");
} else {
let formData = new FormData();
formData.append("videoname_give", videoNameVal.value);
formData.append("videodesc_give", videoDescVal.value);
formData.append("videolink_give", videoLinkVal.value);
formData.append("id_give", boardId);
formData.append("url_give", imgUrl);
console.log(imgUrl);
느낀점: 다른사람과 같이 협업으로 코드를 짜는게 처음이어서 조금 낯설고 어색했지만 너무 재밌고 희귀한 경험이어서 좋았다고 느꼈다. 하지만 깃과 깃허브를 사용하고 다루는게 많이 서툴러서 계속해서 연습해야겠다고 느꼈고, 3일이라는 짧은시간동안 우리 조원분들과 같이 작은 서비스를 만들어보니 웹의 전체적인 흐름에 대해서 아주조금이지만 이해할 수 있어서 정말 좋았다. 그리고 가장 중요하다고 느낀점은 데이터의 흐름이라는 생각이 들었다 데이터가 값으 받아와졌는지 확인하고 어디에서 어디로 흘러가서 db에 저장되는지 같은부분들을 느낄 수 있어서 좋았던 경험이었다.
깃허브주소:DevView 깃허브