Tiny Star

🏕️내일배움캠프/📂팀원 소개 페이지 만들기(23.05.15)

팀원 소개 페이지 3일차-멤버 소개 git으로 코드 합치기

청크 2023. 5. 17. 21:37

스파르타 코딩클럽_내일 배움 캠프 spring 트랙 6기

[프로젝트] 팀 소개페이지 미니 프로젝트

2023.05.15 ~ 2023.05.19

<프로젝트 정보>

개발도구 : Visual Studio Code

프로그래밍 언어 : Python

데이터베이스 : MongoDB

프레임워크 : Flask

라이브러리 : venv

와이어프레임 : Figma

 

<프로젝트 내용>

기존에 작성했던 파일을 git을 사용하여 팀원들이 만든 페이지를 합쳤다.

완성된 페이지는 아니지만 git, branch를 사용하는 방법을 익혔고, 많이 사용해보는 중이다.

 

<index.html>

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <title>Document</title>


    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Alfa+Slab+One&display=swap" rel="stylesheet">

    <title>Member</title>

    <style>
        @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR&display=swap');

        * {
            font-family: 'Noto Sans KR', sans-serif;
        }

        .wrap {
            /* 웹종반 1-9 강의 참고 */
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;

            width: 1320px;
            height: 1500px;

            margin: 0px auto 0px auto;
        }

        #main_banner {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: center;

            width: 1320px;
            height: 300px;

            background-size: cover;
            background-repeat: no-repeat;
        }

        #main_title {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: center;

            padding: 0px 0px 10px 0;
            font-size: 80px;
            font-weight: bold;
            font-family: 'Alfa Slab One', cursive;
            letter-spacing: 6px;

            color: white;
            text-shadow: -1px 0 #000, 0 2.5px #000, 1.5px 0 #000, 0 -1px #000;
        }

        #nav {
            width: 1320px;
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: center;
            margin: 0px;
            border: 0.5px solid gainsboro;
        }

        div>ol {
            display: flex;
            flex-direction: row;
            align-items: right;
            justify-content: right;
            margin-right: 40px;
        }

        div>ol>li {
            margin: 0px 30px 0px 30px;
            list-style: none;
            font-weight: bold;
            height: 25px;
            font-size: 24px;
        }

        /* 여기까지 팀원1  */
        /* 아래는 팀원2 */
        .teamtitle {
            text-align: center;
        }

        .team-body {
            background-color: grey;
            width: 300px;
            height: 100px;
            margin: 20px auto 80px auto;
        }

        .card-header {
            font-size: x-large;
            text-align: center;
        }

        .card-text {
            text-align: center;
        }

        .team-text {
            margin: 20px auto 20px auto;
        }

        .card-title {
            color: white;
            text-align: center;
            background-color: dimgrey;
        }

        .teamintro {
            margin-bottom: 50px;
        }

        /* 여기까지는 팀원2 */

        /* 아래는 팀원3 */

        .title {
            padding: 30px;
        }

        .name {
            margin: auto;

        }

        .card {
            border-color: white;
        }

        .click_img {
            width: 200px;
            height: 200px;
            border-radius: 100%;

        }

        /* 아래는 팀장 : guset book*/


        /* 여기까지 팀장  */
    </style>
    <script type="text/javascript">
        function profile() {
            popupWindow = window.open();
            popupWindow.resizeTo(430, 660);
            popupWindow.onresize = (_ => {
                popupWindow.resizeTo(430, 660);
            })
        }


        function getButton() {
            fetch("/test").then(res => res.json()).then(data => {
                alert(data['msg'])
            })
        }

        function postButton() {
            let formData = new FormData();
            formData.append("title_give", "블랙팬서");

            fetch("/test", { method: "POST", body: formData }).then(res => res.json()).then(data => {
                alert(data['msg'])
            })
        }


        function save_comment() {
            let name = $('#name').val()
            let comment = $('#comment').val()

            let formData = new FormData();
            formData.append("name_give", name);
            formData.append("comment_give", comment);

            fetch('/guestbook', { method: "POST", body: formData, }).then((res) => res.json()).then((data) => {
                alert(data["msg"]);
                window.location.reload()
            });
        }


        $(document).ready(function () {
            show_comment();
        });

        function show_comment() {
            fetch('/guestbook').then((res) => res.json()).then((data) => {
                let rows = data['result']
                $('#comment-list').empty()
                rows.forEach((a) => {
                    let name = a['name']
                    let comment = a['comment']
                    let temp_html = `<div class="card">
                              <div class="card-body">
                                <blockquote class="blockquote mb-0">
                                  <div style="width:100px; height:70px; border:1px solid grey; float:left;">
                                  ${comment}
                                  </div>
                                  <div style="width:150px; height:70px; border:1px solid grey; float:right;">
                                  <footer class="blockquote-footer">${name}</footer>
                                  </div>
                                </blockquote>
                              </div>
                            </div>`
                    $('#comment-list').append(temp_html)
                })

            })
        }
    </script>
</head>

<body>
    <div class="wrap">
        <div id="main_banner">
            <div>
                <div>
                    <h1 id="main_title">
                        <p>E 1 I 4</p>
                    </h1>

                </div>
                <div>
                    <h1>
                        <p> &nbsp&nbsp;</p>
                    </h1>

                </div>
            </div>
        </div>
        <div id="nav">
            <ol>
                <li>E1I4 Intro</li>
                <li>Member</li>
                <li>Design_Empty</li>
                <li>Guest Book</li>
            </ol>
        </div>


        <div class="teamintro" style="align-items: center">
            <div class="card-body">
                <img src="/static/image/banner.png" class="card-img-top" alt="...">
                <h5 class="card-text">안녕하세요, 저희는 E 1명과 I 4명으로 구성된 화목한 5남매(+1) 입니다 🙋🏻‍♂️🧚🏻‍♂️👩🏻🐶👩🏻‍🦰👰🏻‍♀️
                </h5>
                <h5>모두 비전공자이고 나이도 다르지만, 프로젝트를 완성하고자 의기투합하여 한 마음 한 뜻으로 똘똘 뭉쳤습니다 V</h5>

            </div>
        </div>
        <div class="teaminfo">
            <div class="row row-cols-1 row-cols-md-3 g-4">
                <div class="col">
                    <div class="card h-100">
                        <div class="card-body">
                            <h5 class="card-title">TMI / 우리팀의 특징</h5>
                            <img src="/static/image/Frame 6.png" class="card-img-top" alt="...">
                        </div>
                    </div>
                </div>
                <div class="col">
                    <div class="card h-100">
                        <div class="card-body">
                            <h5 class="card-title">궁극적인 목표</h5>
                            <P></P>
                            <p class="card-text"> ✔ Git 사용법 숙지</p>
                            <p class="card-text"> ✔ 내일배움캠프 포기하지 않고 끝까지 수료하기!</p>
                            <p class="card-text"> ✔ 프론트와 백의 연결관계 이해하기</p>
                            <p class="card-text"> ✔ POST, GET 사용법 마스터하기</p>
                            <p class="card-text"> ✔ ch1 미니 project 구조 정확히 이해하고 만들기</p>
                        </div>
                    </div>
                </div>
                <div class="col">
                    <div class="card h-100">
                        <div class="card-body">
                            <h5 class="card-title">우리팀의 규칙</h5>
                            <P></P>
                            <p class="card-text"> ✔ 건강이 제일 중요! 밥 세끼 꼬박꼬박 잘 챙겨먹기💕</p>
                            <p class="card-text"> ✔ 막히는 부분이 있다면 혼자 머리싸매지 말고 팀원과 같이 해결!</p>
                            <p class="card-text"> ✔ 13-14시 점심 시간, 18-19시 저녁 시간 🐷</p>
                            <p class="card-text"> ✔ 20시 Git Merge 후 팀원들과 함께 코드리뷰 , 상세 피드백하기</p>
                            <p class="card-text"> ✔ 20시 40분 개발 일지(TIL) 작성하고 퇴실시간 맞춰 퇴실하기</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>


        <div class="title">
            <h2>MEMBER</h2>
        </div>
        <div class="member">
            <div class="row row-cols-1 row-cols-md-5 g-2">
                <div class="col">
                    <div class="card h-100">
                        <img src="https://ca.slack-edge.com/T043597JK8V-U053UK80VR8-cbc4d9e1783b-512" class="click_img"
                            alt="...">
                        <div class="name">
                            <h3>팀장</h3>
                        </div>
                    </div>
                </div>
                <div class="col">
                    <div class="card h-100">
                        <img src="https://ca.slack-edge.com/T043597JK8V-U051WD9LCNP-45ff45329ac6-512"
                            class="click_img alt=" ... onclick="profile()">
                        <div class="name">
                            <h3>팀원</h3>
                        </div>
                    </div>
                </div>
                <div class="col">
                    <div class="card h-100">
                        <img src="https://ca.slack-edge.com/T043597JK8V-U0532LT9LLE-58e265f5a665-512" class="click_img"
                            alt="..." onclick="profile()">
                        <div class="name">
                            <h3>팀원</h3>
                        </div>
                    </div>
                </div>
                <div class="col">
                    <div class="card h-100">
                        <img src="https://ca.slack-edge.com/T043597JK8V-U052A5UUG06-fd387358fc87-512" class="click_img"
                            alt="..." onclick="profile()">
                        <div class="name">
                            <h3>팀원</h3>
                        </div>
                    </div>
                </div>
                <div class="col">
                    <div class="card h-100">
                        <img src="https://ca.slack-edge.com/T043597JK8V-U053QSM8MT4-e435cca492ea-512" class="click_img"
                            alt="..." onclick="profile()">
                        <div class="name">
                            <h3>팀원</h3>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div>
            <button onclick="location.href='/myprofile/new'">상세페이지</button>
        </div>

        <div class="mypic">
            <h1>GUEST BOOK</h1>
        </div>
        <div class="mypost">
            <div class="form-floating mb-3">
                <input type="text" class="form-control" id="name" placeholder="닉네임" />
            </div>
            <div class="form-floating">
                <textarea class="form-control" placeholder="방명록을 작성하세요" id="comment" style="height: 100px"></textarea>
            </div>
            <button onclick="save_comment()" type="button" class="btn btn-dark">
                댓글 남기기
            </button>
        </div>
        <div class="mycards" id="comment-list">
            <div class="card">
                <div class="card-body">
                    <blockquote class="blockquote mb-0">
                        <p>새로운 앨범 너무 멋져요!</p>
                        <footer class="blockquote-footer">호빵맨</footer>
                    </blockquote>
                </div>
            </div>
            <div class="card">
                <div class="card-body">
                    <blockquote class="blockquote mb-0">
                        <p>새로운 앨범 너무 멋져요!</p>
                        <footer class="blockquote-footer">호빵맨</footer>
                    </blockquote>
                </div>
            </div>
            <div class="card">
                <div class="card-body">
                    <blockquote class="blockquote mb-0">
                        <p>새로운 앨범 너무 멋져요!</p>
                        <footer class="blockquote-footer">호빵맨</footer>
                    </blockquote>
                </div>
            </div>
        </div>
    </div>
</body>

</html>

<sub.html>

<!DOCTYPE html> 
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>

    <link href="https://fonts.googleapis.com/css2?family=Gowun+Batang:wght@400;700&display=swap" rel="stylesheet" />

    <title>상세페이지</title>

    <style>
        ::selection {
            user-select: none
                /* 드래그 못하게 */
        }

        ::-webkit-scrollbar {
            width: 10px;
        }

        ::-webkit-scrollbar-thumb {
            background-color: #2f3542;
            border-radius: 10px;
            background-clip: padding-box;
            border: 2px solid transparent;
        }

        .container::-webkit-scrollbar-track {
            background-color: grey;
            border-radius: 10px;
            box-shadow: inset 0px 0px 5px white;
        }

        .imoge {
            position: absolute;
            width: 49px;
            height: 41px;
            left: 523px;
            top: 151px;

            font-family: 'Inter';
            font-style: normal;
            font-weight: 400;
            font-size: 70px;
            line-height: 85px;
            /* background-color: red; */
            text-shadow: 0px 8px 20px rgba(0, 0, 0, 0.25);
        }

        .photo {
            box-sizing: border-box;
            position: absolute;
            width: 293px;
            height: 283px;
            left: 523px;
            top: 248px;
            box-shadow: 0px 8px 20px rgba(0, 0, 0, 0.25);
            border-radius: 50px;
            background-image: url('https://cdn.pixabay.com/photo/2023/04/03/03/20/plant-7895897_1280.jpg');
            background-repeat: no-repeat;
            background-position: center;
        }

        .name {
            position: absolute;
            width: 250px;
            height: 77px;
            left: 890px;
            top: 296px;
            font-family: 'Inter';
            font-weight: 600;
            font-size: 60px;
            line-height: 77px;
        }

        .about_me_area {
            position: absolute;
            width: 288px;
            height: 158px;
            left: 905px;
            top: 373px;
            background: transparent;
        }

        .about_me_text {
            font-style: normal;
            font-weight: 400;
            font-size: 16px;
            line-height: 20px;
        }

        #tmi_area {
            position: absolute;
            width: 864px;
            height: 323px;
            left: 523px;
            top: 566px;
            background: rgba(217, 217, 217, 0.22);
            box-shadow: 0px 8px 20px rgba(0, 0, 0, 0.25);
            border-radius: 80px;
        }

        .profile {
            position: absolute;
            left: 80px;
            top: 40px;
            font-family: 'Roboto';
            font-style: normal;
            font-weight: 567;
            font-size: 48px;
            line-height: 56px;
            font-variant: small-caps;
        }

        .text {
            background-color: transparent;
            position: absolute;
            left: 100px;
            top: 100px;
            font-family: 'Inter';
            font-style: normal;
            font-weight: 400;
            font-size: 17px;
        }

        .text:hover {
            outline: none;
            cursor: pointer
        }

        summary::marker {
            content: "+ ";
            font-family: monospace;
            font-size: 16px;
        }

        details[open] summary::marker {
            content: "- ";
        }

        .button {
            border: none;
            position: absolute;
            width: 133px;
            height: 53px;
            left: 1262px;
            top: 911px;

            background: #4A99E9;
            color: white;
            box-shadow: 0px 8px 10px rgba(0, 0, 0, 0.25);
            border-radius: 50px;
        }

        .button:hover {
            background: #3E81C4;
        }

        .button:active {
            transform: scale(0.95);
        }
    </style>

    <script>
        window.addEventListener('DOMContentLoaded', function () {
            document.querySelectorAll('details').forEach(function (item) {
                item.addEventListener("toggle", event => {
                    let toggled = event.target;
                    if (toggled.attributes.open) {
                        document.querySelectorAll('details[open]').forEach(function (opened) {
                            if (toggled != opened)
                                opened.removeAttribute('open');
                        });
                    }
                })
            });
        });

        $(document).ready(function () {
            show_profiles();
            console.log("ready")
        });
        function show_profiles() {
            fetch('/myprofile/new1').then(res => res.json()).then(data => {
                let rows = data['result']
                console.log(rows)
                $('#container').empty();
                rows.forEach((a) => {    
                    let imoge = a['imoge']
                    let photo = a['photo']
                    let name = a['name']
                    let about_me = a['about_me']
                    let q1 = a['q1']
                    let q2 = a['q2']
                    let q3 = a['q3']
                    let q4 = a['q4']
                    
                    let temp_html = `<div class="container" id="container">
                                        <div>
                                            <text class="imoge">${imoge}</text>
                                        </div>
                                        <div class="photo">${photo}</div>
                                        <div>
                                            <text id="name" class="name">${name}</text>
                                        </div>
                                        <div id="test" class="about_me_area">
                                            <text class="about_me_text">${about_me}</text>
                                        </div>

                                        <div id="tmi_area">
                                            <text class="profile">
                                                Profile
                                            </text>
                                            <div class="text">
                                                <details>
                                                    <summary>사용할 수 있는 언어</summary>
                                                    <p>${q1}</p>
                                                </details>

                                                <details>
                                                    <summary>자신의 장점</summary>
                                                    <p>${q2}</p>
                                                </details>

                                                <details>
                                                    <summary>나의 MBTI</summary>
                                                    <p>${q3}</p>
                                                </details>

                                                <details>
                                                    <summary>TMI</summary>
                                                    <p>${q4}</p>
                                                </details>
                                            </div>
                                        </div>
                                        <button type="button" onclick="location.href='http://localhost:5000/' " class="button">뒤로가기</button>
                                    </div>`
                    $('#container').append(temp_html)
                })
            })
        }
    </script>
</head>

<body>
<div class="container" id="container">
    <div>
        <text class="imoge">🐶</text>
    </div>
    <div class="photo"></div>
    <div>
        <text class="name">이름</text>
    </div>
    <div id="test" class="about_me_area">
        <text class="about_me_text">자기소개</text>
    </div>

    <div id="tmi_area">
        <text class="profile">
            Profile
        </text>
        <div class="text">
            <details>
                <summary>사용할 수 있는 언어</summary>
                <p>내부에 넣을 내용을 입력해주세요</p>
            </details>

            <details>
                <summary>자신의 장점</summary>
                <p>내부에 넣을 내용을 입력해주세요</p>
            </details>

            <details>
                <summary>나의 MBTI</summary>
                <p>내부에 넣을 내용을 입력해주세요</p>
            </details>

            <details>
                <summary>TMI</summary>
                <p>내부에 넣을 내용을 입력해주세요</p>
            </details>
        </div>
    </div>
    <button type="button" onclick="location.href='http://localhost:5000/' " class="button">뒤로가기</button>
</div>
</body>

<app.py>

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

# mongoDB는 OOO - 본인 mongoDB로 변경하기
from pymongo import MongoClient

client = MongoClient('mongodb+srv://sparta:test@cluster0.ziorpfn.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

@app.route('/')
def home():
    return render_template('index.html')

@app.route("/myprofile/new", methods=["GET"])
def post_profile():

    return render_template('sub.html')

@app.route("/myprofile/new1", methods=["GET"])
def profiles_get():
    all_profiles = list(db.profiles.find({}, {'_id': False}))

    return jsonify({'result': all_profiles})

@app.route('/sub')
def sub():
    return render_template('sub.html')

@app.route('/test', methods=['GET'])
def test_get():
    title_receive = request.args.get('title_give')
    print(title_receive)
    return jsonify({'result':'success', 'msg': '이 요청은 GET!'})


# 방명록 저장하는 곳
@app.route('/guestbook', methods=['POST'])
def guestbook_post():
   name_receive = request.form['name_give']
   comment_receive = request.form['comment_give']
   doc = {
       'name'  :name_receive,
       'comment' : comment_receive
   }
   db.guestbook_comments.insert_one(doc)
   return jsonify({'msg': '방명록이 등록되었습니다!'})

# 방명록 mongDB에서 index.html로 데이터 전송
@app.route("/guestbook", methods=["GET"])
def guestbook_get():
    all_comments = list(db.guestbook_comments.find({},{'_id':False}))
    #db.user.find 에서 users 바꿔야한다 일단 강의대로 fan으로 저장함
    #fan -> guestbool_comments 로 변경
    return jsonify({'result': all_comments})

# mac 사용자는 포트5001로 변경하세요.
if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)