ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [solo project] My Agora States
    codeStates front-end/Git(project) 2023. 1. 10. 14:12
    반응형

     

     

     

     

     

    나의 아고라 스테이츠 만들기

     

    회고

     

    Bare Minimum Requirement

    • 디스커션 나열 기능
      • script.js를 수정하여 agoraStatesDiscussions 배열의 데이터를 나열할 수 있게 구현합니다.
    • CSS
      • 아고라 스테이츠 질문 리스트가 중앙으로 와야 합니다.
      • style.css를 수정하여 멋지고 아름답게 나만의 아고라 스테이츠를 꾸밉니다.
      • colorhunt, dribbble에서 적절한 색 조합, 디자인을 참고합니다.
    • 디스커션 추가 기능
      • script.js를 수정하여 디스커션 추가 기능을 구현합니다.
      • section.form__container 요소에 새로운 아고라 스테이츠 질문을 추가할 수 있는 입력 폼을 제작합니다. 형식은 자유입니다.
      • 아이디, 본문을 입력하고 버튼을 누르면 실제 화면에 디스커션이 추가되어야 합니다.
      • agoraStatesDiscussions 배열에 추가한 데이터가 실제 쌓여야 합니다.

    Advanced Challenge

    • 현지 시간 적용
      • 샘플 시간을 잘 변형하여, 현지 시간에 맞게 표현합니다. (ex. 오전 10:02:17)

     

     

    까지 진행 하였다

     

     

     

    style.css

     

     

    *{
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        font-family: 'Noto Sans KR', sans-serif;
        font-family: 'Ubuntu', sans-serif;
    }
    /* 브라우저 초기화 */
    
     @import url('https://fonts.googleapis.com/css?family=Amatic+SC');
    
    body {
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: black;
        background-repeat:no-repeat;
        background-size: cover;
    }  
    
    .form__input--title > label {
        word-spacing : 7px;
        color: white;
    }
    
    .form__input--name > label {
        word-spacing : 3px;
        color: white;
    }
    
    h2 {
        font-family: 'Nanum Brush Script', cursive;
        color: #99bcda;
    }
    section.form__container {
        background-color: rgb(10, 38, 71);
        border-style: dashed;
        border-color: #00E7FF;
        border-radius: 20px;
    }
    .discussion__answered {
        padding-top: 39px;
        font-size: 20px;
        margin: 5px;
        color: #FFF9CA;
    
    }
    .discussion__container {
        border-style: dashed;
        border-color: #00E7FF;
        display: flex;
        justify-content: space-between;
        align-items: center;
        width: 578px;
        height: 150px;
        font-size : 10px;
        border-radius: 19px;
        margin : 10px;
        padding: 20px;
    }
    .discussion__avatar--image {
        width: 48px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        margin: 5px;
    }
    .discussion__content{
        display: block;
    }
    .discussion__content >:nth-child(1){
     width: 440px;
     text-align: left;
     margin-top: 0;
    }
    .discussion__content >:nth-child(2){
        height:30px;
        text-align: right;
    }
    li {
        list-style-type: none;
    }
    section.discussion__wrapper{
        display: flex;
        flex:4;
        width: 578px;
        justify-content: center;
        align-items:center;
    }
    ul {
        padding: 0px;
    }
     li.discussion__container {
         background-color: #144272;
    } 
    a:link {
        color: white;
        font-family: 'Dongle', sans-serif;
        font-size: 17px;
    }
    a:visited {
         color: rgb(0, 0, 0); 
    }
    
    /* 폼 디자인 */
    h1 {
        text-align: center;
        margin-top: 70px;
        margin-bottom: 20px;
        color: #205295;
        font-size: 40pt;
    }
    h3 {
        text-align: center;
        color: #99bcda;
        margin-bottom: 20px;
    }
    section {
        display:flex;
        justify-content: center;
        align-items: center;
    }
    form {
        display: flex;
        width: 500px;
        flex-wrap: wrap;
        flex-direction: row;
    }
    .form__textbox {
        display: flex;
        flex-direction: column;
        color: white;
    }
    #name {
        background-color: #144272;
        border-style: hidden;
    }
    #story {
        width: 500px;
        border-radius: 10px;
        padding: 10px;
        background-color: #144272;
        border-style: hidden;
    }
    .form__input--wrapper {
        margin: 5px;
    
    }
    .form__input--wrapper input {
        width:300px;
        height: 30px;
        font-size:1.2rem;
        margin: 5px;
        border-radius: 10px;
        border: 2px solid #0078AA;
    }
    .form__submit {
        flex:1;
        margin:3px;
    
    }
    .form__submit input {
        color : white;
        background-color: #144272;
        width: 100px;
        height: 43px;
        border-radius: 10px;
        font-size: 15px;
        margin-left: 400px;
        margin-right: 0px;
        border-style: hidden;
    }
    textarea {
        margin : 5px;
    }
    
    .discussion__information {
        padding-top: 10px;
        font-size: 14px;
        /* color: #FFF9CA; */
    }
    
    img {
        width: 48px;
        border-radius: 100%;
    }

     

     

    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">
      <title>My Agora States</title>
      <link rel="stylesheet" href="style.css">
    
      <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.8/purify.js"
        integrity="sha512-QaF+0tDlqVmwZaQSc0kImgYmw+Cd66TxA5D9X70I5V9BNSqk6yBTbyqw2VEUsVYV5OTbxw8HD9d45on1wvYv7g=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
        
    </head>
    
    <body>
      <main>
        <h1>My Agora States</h1>
        <section class="form__container">
          <form action="" method="get" class="form">
            <div class="form__input--wrapper">
              <div class="form__input--name">
                <label for="name">Enter your name: </label>
                <input type="text" name="name" id="name" required>
              </div>
              <div class="form__input--title">
                <label for="name">Enter your title: </label>
                <input type="text" name="name" id="name" required>
              </div>
              <div class="form__textbox">
                <label for="story">Your question: </label>
                <textarea id="story" name="story" placeholder="enter your question" required></textarea>
              </div>
            </div>
            <div class="form__submit">
              <input type="submit" value="submit">
            </div>
          </form>
        </section>
        <section class="discussion__wrapper">
          <ul class="discussions__container">
            <li class="discussion__container">
              <div class="discussion__avatar--wrapper">
                <img class="discussion__avatar--image"
                  src="https://avatars.githubusercontent.com/u/12145019?s=64&u=5c97f25ee02d87898457e23c0e61b884241838e3&v=4"
                  alt="avatar of kimploo">
              </div>
              <div class="discussion__content">
                <h2 class="discussion__title"><a href="https://github.com/codestates-seb/agora-states-fe/discussions/6">[notice] 좋은 질문하는 법</a></h2>
                <div class="discussion__information">kimploo / 2022-04-22T14:08:33Z</div>
              </div>
              <div class="discussion__answered"><p>☑</p></div>
            </li>
          </ul>
        </section>
      </main>
    </body>
    <script src="data.js"></script>
    <script src="script.js"></script>
    
    
    </html>

     

     

    script.js

     

    // index.html을 열어서 agoraStatesDiscussions 배열 요소를 확인하세요.
    console.log(agoraStatesDiscussions);
    
    // convertToDiscussion은 아고라 스테이츠 데이터를 DOM으로 바꿔줍니다.
    const convertToDiscussion = (obj) => {
      const li = document.createElement("li"); // li 요소 생성
      li.className = "discussion__container"; // 클래스 이름 지정
    
      const avatarWrapper = document.createElement("div");
      avatarWrapper.className = "discussion__avatar--wrapper";
      const discussionContent = document.createElement("div");
      discussionContent.className = "discussion__content";
      const discussionAnswered = document.createElement("div");
      discussionAnswered.className = "discussion__answered";
    
    
        // TODO: 객체 하나에 담긴 정보를 DOM에 적절히 넣어주세요.
    
        // 프로필 사진 넣어주기
        const face = document.createElement("img") // 프로필 사진
        face.src = obj.avatarUrl;
        face.alt = "avatar of" + obj.author;
        //my error point
        face.className = "discussion__avatar--image";
        avatarWrapper.append(face);
    
       // 스테이츠 속 질문 제목을 선언 url을 타고 깃허브로 간다
       // h2로 선언된 변수가 질문 제목
      const discussionTitle = document.createElement("h2");
      // a로 선언된 변수가 질문 속 url
      const titleAnchor = document.createElement("a");
      titleAnchor.href = obj.url;
      titleAnchor.textContent = obj.title;
      // 만든 질문 제목과 url을 적용
      discussionTitle.append(titleAnchor);
      discussionContent.append(discussionTitle);
    
      // div로 선언된 질문 속 정보 선언 
      const discussionInfo = document.createElement("div");
      // 저자가 누군지 문자열 리터럴로 선언
      discussionInfo.textContent = `${obj.author} / ${new Date(obj.createdAt).toLocaleTimeString()}` 
      // 질문 내용 적용
      discussionContent.append(discussionTitle, discussionInfo);
    
      // 질문 속 체크박스 생성 
      // p 태그로 선언된 checked
      const checked = document.createElement("p");
      // textcontent는 텍스트를 추가할 수 있는 프로퍼티
      checked.textContent = obj.answer ? "☑︎" : "☒";
      // checked 적용
      discussionAnswered.append(checked);
    
    
      li.append(avatarWrapper, discussionContent, discussionAnswered);
      return li;
    };
    
    
    // agoraStatesDiscussions 배열의 모든 데이터를 화면에 렌더링하는 함수입니다.
    const render = (element) => {
      for (let i = 0; i < agoraStatesDiscussions.length; i += 1) {
        element.append(convertToDiscussion(agoraStatesDiscussions[i]));
      }
      return;
    };
    
    // ul 요소에 agoraStatesDiscussions 배열의 모든 데이터를 화면에 렌더링합니다.
    const ul = document.querySelector("ul.discussions__container");
    render(ul);
    
    form.addEventListener("submit", 
    (event) => {
      event.preventDefault(); //서브밋 이벤트로 사용시 꼭 함께 사용해주어야함
      // addEventListener 안으로 선언 위치 이동
      const author = form.querySelector("div.form__input--name > input").value;
      const title = form.querySelector("div.form__input--title > input").value;
      const textbox = form.querySelector("div.form__textbox > textarea").value;
    
      const Obj = {
        id: "new id",
        createdAt: new Date().toISOString(),
        title: title,
        url: "https://github.com/codestates-seb/agora-states-fe/discussions",
        author: author,
        bodyHTML: textbox,
        avatarUrl: "https://avatars.githubusercontent.com/u/97888923?s=64&u=12b18768cdeebcf358b70051283a3ef57be6a20f&v=4"
      }
    // addEventListener 안으로 선언 위치 이동
      **agoraStatesDiscussions.unshift(newObj);
    
      const discussion = convertToDiscussion(newObj);
      
      ul.prepend(discussion);
    
      // submit 후 입력란 빈칸으로 리셋하는 기능 추가
      form.querySelector("div.form__input--name > input").value = "";
      form.querySelector("div.form__input--title > input").value = "";
      form.querySelector("div.form__textbox > textarea").value = "";
    }
    )

     

     

     

     

     

    배포 화면

     

     

     

     

    Git 풀리퀘 완료

     

     

     

     

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------

     

     

     

    느낀점

     

    css

     

     

    이렇게 되길 원했지만 적당한 이모지도 못 찾고 생각보다 어려웠다 ㅜ

    오픈소스가 있는 css (bootstrap) 으로 다음엔 완성도 있게 만들어봐야겠다

     

    JS

     

    생각보다 데이터 적재와 페이지네이션이 구현이 어려워 하지 못했다.

    시간이 좀 더 많았으면 가능했을 것 같은데 더 해봐야겠다 끝!

     

     

    반응형

    댓글

Designed by Tistory.