목금 이틀동안 솔로 프로젝트로 나만의 아고라스테이츠를 만들어보았다.
섹션1에서 배웠던 개념들을 모두 사용하여 하나의 웹페이지를 구현해보는 프로젝트였다. 사실 예전에 졸업 프로젝트를 만든다던가 해커톤이나 종종 프로젝트를 참여한 적이 있어 큰 부담은 없었던 거 같다. 하지만 확실히 느낀건 그때보다 지금의 내가 훨씬 성장했다는 점이다.
예전에 화면 레이아웃을 구성할 때 flex 박스 사용방법을 잘 몰라 아무곳이나 다 flex를 때려박고 고생을 했던 기억이있는데 섹션 1에서 학습한 대로 부모요소에 적용하는 속성과 자식요소에 적용하는 속성을 따로 두어 적용하니 수월하게 레이아웃을 손 볼 수 있었다.
그럼 서론은 여기까지 적고 아고라스테이츠를 구현하면서 느낀점이나 어려웠던 점 알게된 점을 중심으로 글을 작성해보겠다.
개요
기초적인 틀은 제공 받은 상태이고 데이터 또한 미리 저장되어있는 상태였다. 프론트 혼자 작업하는 것이기 때문에 데이터를 미리 저장해 둔 것 같다.
기본적으로 프로젝트에서 요구하는 사항으로는 아래와 같다.
1. 디스커션 나열기능
2. CSS
3. 디스커션 추가 기능
4. Github page 배포
추가적으로 요구하는 사항으로는 아래와 같다.
1. 현지 시간 적용
2. 페이지네이션 기능
3. 디스커션 유지 기능 (LocalStorage를 활용 )
디자인
첫번째로 시작한 것은 디자인을 생각해보는 것이었다. 저번 페어 프로젝트로 진행한 계산기 만들기도 기능 구현은 모두 완료하였지만 후에 디자인에 시간을 많이 투자했던 거같다. 따라서 이번에는 피그마를 활용하여 디자인을 먼저 생각해보았다. 피그마에 대해 배운적은 없었지만 예전에 기획디자인분들과 협업을 했을 때 피그마를 사용하여 디자인을 받았던 것을 떠올려 피그마를 사용해보았다.
왼쪽 상단이 css 적용전 컴포넌트로 나누어 데이터 리스트를 불러온 사이트이고 오른쪽 하단이 참고한 사이트 왼쪽 하단이 내가 생각한 웹 디자인이었다. 그런데 문뜩 네온이 들어간 제목을 넣고 싶다는 생각이 들었고 레이아웃은 유지하지만 디자인을 전면 수정하기로 하였다. (즉흥적으로 아이디어가 생각났기 때문에 피그마로는 만들지 못했다.)
2차 디자인을 완성하고 나니 네온 사인을 살리긴 했지만 글에 집중하기에 어려운거 같다는 생각에 네온은 살리면서 다른 방법이 없을까 고민하던중 보랏빛 밤 하늘이 생각이 났고 밤 하늘을 보며 종종 생각에 잠기는 나를 생각하면서 웹 사이트에 취지와 맞다고 생각했고 디자인을 다시 수정하였다.
보랏빛 네온으로 물든 밤하늘을 연상시키는 디자인을 완성했다 ! 정말 마음에 들었다. 디자인에 맞게 글꼴도 수정하고 스크롤바 디자인도 따로 수정하였다.
기능구현
기본적으로 요구하는 기능은 모두 충족하였다. 디스커션 나열 기능은 DOM 을 배운 부분을 활용하여 데이터가 들어올 때마다 기초 틀에 맞게 요소들을 생성해주고 append 해주는 형식으로 데이터를 가져와 나열했다.
HTML 구조
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://kit.fontawesome.com/f7e828b58e.js" crossorigin="anonymous"></script>
<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>
<section class="title_form">
<h1 class="titleAgora">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 class="formstyle" type="text" name="name" id="name" required>
</div>
<div class="form__input--title">
<label for="title">Enter your title: </label>
<input class="formstyle" type="text" name="title" id="title" required>
</div>
<div class="form__textbox">
<label for="story">Your question: </label>
<textarea class="formTextboxStyle" id="story" name="story" placeholder="질문 작성! " required></textarea>
</div>
</div>
<div class="form__submit">
<input class="submit" type="submit" value="submit">
</div>
</form>
</section>
</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">
<i class="fa-solid fa-check"></i>
</div>
</li>
</ul>
</section>
<!-- <section class="moreShow">
<button class="moreBtn">More</button>
</section> -->
</main>
</body>
<script type="module" src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.js"></script>
<script src="data.js"></script>
<script src="script.js"></script>
</html>
JS
디스커션 나열 기능
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";
// 객체 하나에 담긴 정보를 DOM에 적절히 넣는다.
//이미지 객체 추가
const avatarImg = document.createElement('img');
avatarImg.className = "discussion__avatar--image";
avatarImg.src = obj.avatarUrl;
avatarImg.alt = 'avatar of ' + obj.author;
avatarWrapper.append(avatarImg);
//컨텐츠 객체 추가 (제목 ,제목 url)
const discussionTitle = document.createElement("h2");
discussionTitle.className = "discussion__title";
const discussionTitleUrl = document.createElement("a");
discussionTitleUrl.textContent = obj.title;
discussionTitleUrl.href = obj.url;
discussionTitle.append(discussionTitleUrl);
const discussionInfo = document.createElement("div");
discussionInfo.className = "discussion__information";
discussionInfo.textContent = obj.author;
discussionInfo.textContent += ' / ' +new Date(obj.createdAt).toLocaleString();
discussionContent.append(discussionTitle,discussionInfo);
// 답변 객체 추가
const discussionAns = document.createElement('i');
// discussionAns.className ="fa-solid fa-check";
if(obj.answer !== null){
discussionAns.className ="fa-solid fa-check";
}
else{
discussionAns.className = "fa-solid fa-xmark";
}
discussionAnswered.append(discussionAns);
li.append(avatarWrapper, discussionContent, discussionAnswered);
return li;
};
convertToDiscussion 함수는 obj 를 인자로 하여 리스트를 리턴해준다. 즉 하나의 데이터 객체 당 하나의 리스트요소로 만들어 ul 태그에 붙히기 위함이다.
현지 시간 적용
new Date 를 활용해 현지 시간을 적용하였고 toLocaleStiring()을 붙혀주어 불필요한 텍스트는 제거해주었다.
Date() 만 사용할 시 인수를 무시하며 현재 날짜 및 시간을 나타내는 문자열을 반환한다. new Date () 는 Date 타입인 새로운 객체를 를 생성한다 . 따라서 나는 new Date 를 사용해주었고 .지정된 지역에서 사용하는 숫자의 표현방식으로 문자열을 리턴해주는 toLocaleString() 을 통해 2023.03.11 오후 10:00 이러한 형식으로 시간을 나타내주었다.
디스커션 추가 기능
사용자가 form 에 데이터를 입력했을 때 데이터에 추가하고 리스트를 화면에 띄어줘야한다. 따라서 이벤트 함수를 사용하여 submit 버튼이 클릭되었을 때 객체를 생성하고 기존 데이터에 추가해주며 ul에 붙혀주는 형식으로 코드를 작성했다.
const form = document.querySelector('.form');
const author = document.querySelector('.form__input--name > input'); //input-name에 입력하는 input 요소들
const title = document.querySelector('.form__input--title > input'); //inp;ut-title에 입력하는 input 요소들
const textArea = document.querySelector('.form__textbox > textarea'); //form_textbox에 입력하는 질문 textarea 요소들
let newobj = JSON.parse(localStorage.getItem("objstorage"));
let localnum = 0;
// 함수form.addEventListener의 'submit'이벤트를 통해 각각의 데이터 정보를 리턴
form.addEventListener('submit', (event) => {
event.preventDefault(); //1)submit눌렀을때 새로고침되는걸 방지
// const convertToDiscussion = (obj)/에 돌려줄 obj 객체를 하나 만든다.
const obj ={
id: "unique number",
createdAt: new Date(),
title: title.value,
url: "https://github.com/baejb/fe-sprint-my-agora-states",
author: author.value,
answer: {
id: "111",
createdAt: "111",
url: "111",
author: "111",
bodyHTML: textArea.value,
avatarUrl: "111",
},
bodyHTML:textArea.value,
avatarUrl:
"https://avatars.githubusercontent.com/u/82064490?s=400&u=9f590e40f0f357bc23e77008d2d0e5ce0ee3f3c0&v=4",
};
// 만든 배열을 data더미의 배열에 추가해준다.(맨 앞 요소로)
agoraStatesDiscussions.unshift(obj);
//전체 데이터 더미를 ul로 append해준다(맨 앞으로->prepend)
ul.prepend(convertToDiscussion(obj));
localStorage.setItem("n"+localnum,JSON.stringify(obj));
// let localstored = JSON.parse(localStorage.getItem("n"+localnum));
localnum ++;
// localStorage.setItem("index",localnum);
//입력한 값을 submit에서 댓글창으로 append 되면 값을 초기화한다.
author.value = "";
title.value = "";
textArea.value = "";
});
디스커션 유지 기능
localStorage에 데이터를 저장하는 방법은 이번에 검색을 통해 새롭게 알게된 사실이었다. 사실 localStorage 를 사용하여 디스커션 유지기능을 완벽하게 구현하지 못하였지만 구현하기 위해 많은 노력은 했었다. 키 값이 같으면 값이 덮어 씌어지는 바람에 제대로 화면에 나오진 않았지만 그래도 localStorage 에 대해 공부해볼 수 있어서 좋았다.
storage 타입은 key - value 쌍을 저장하도록 설계되어있고 메소드로는 아래와같이 존재한다. 또한 length 속성을 사용할 수 있다.
- setItem(name, value) - name을 키로 값을 저장합니다.
- removeItem(name) - 이름에 해당하는 key-value 쌍을 제거합니다.
- getItem(name) - 주어진 이름에 대한 값을 가져옵니다.
- key(index) - 주어진 숫자 위치에 있는 값의 이름을 가져옵니다.
- clear() - 모든 값을 제거합니다.
내가 사용해본 메소드는 setItem ,getItem 이다.
localStorage 에 접근하기 위해서는 window 객체의 속성을 통해 접근할 수 있다.
window.localStorage
우리는 객체를 저장하므로 for 문을 사용했어야 했고 storage 타입은 문자열 데이터만 저장하기 때문에 JSON.stringfy() 메소드를 사용하여 문자열로 바꾼 후 저장해야한다. 또한 다시 불러올 때는 JSON.parse() 로 객체로 만들어주어야했다.
다음번에 localStorage를 사용하는 계기가 있다면 완벽하게 사용할 수 있을 거같다. 페이지네이션 기능은 사실 여러 문서를 찾아보았지만 페이지수에 따라 버튼을 생성하고 페이지를 출력하고 ,, 시간내에 못할 거같아 포기하기도 했다. 하지만 따로 다시 공부후서 페이지네이션도 구현해볼 것이다. ! 이렇게 디자인 , 기능구현까지 마치며 솔로 프로젝트를 마쳤다.
소그룹 회고 시간에 그룹원들이 만든 페이지를 보며 모달창이라던지 모바일에 맞게 화면을 구현한다던지 하는 것을 보고 정말 대단하다고 생각이 들었다. 또한 그룹원 분 한분이 나에게 스크롤바에 대한 질문을 해주셨는데 내가 미쳐 지나친 개념을 바로 잡아 주셔서 정말 감사했다.
솔로 프로젝트를 마치며 2월 초 처음 시작했던 나보다 훨씬 더 성장했다는 것을 느낄 수 있었고 수료하기까지 얼마나 더 성장할지 기대가 되는 활동이었다.
깃허브 페이지 배포
'코드스테이츠44기 프론트엔드' 카테고리의 다른 글
[코드스테이츠 44기 프론트엔드 블로깅] 클래스와 인스턴스에 대해 (0) | 2023.03.15 |
---|---|
[코드스테이츠 44기 프론트엔드 회고록] Section 1 을 마치며 (0) | 2023.03.13 |
[코드스테이츠 44기 프론트엔드 블로깅 ] javascript 개념 정리 (0) | 2023.03.06 |
[코드스테이츠 44기 프론트엔드 10일차 회고록] 우분투 설치 및 CLI 명령 정리 (0) | 2023.02.25 |
[코드스테이츠 44기 프론트엔드 9일차 회고록] 계산기 구현하기-1 (0) | 2023.02.23 |