공통 CSS 파일 필요성
내가 이번에 진행하는 프로젝트는 하나의 페이지만 존재하는 것이 아닌, 페이지 수가 최소 3장 이상인 프로젝트이다.
이 프로젝트 페이지를 하나하나 만들때마다 공통으로 사용되는 것들이 존재한다. 버튼이라던가, 카드, header, footer, 글자 사이즈 및 색상 등…
이 스타일들을 매번 각 페이지에 작성하기에는 비효율적이고 관리하는데도 복잡한 점이 많다. 색상이나 글자 사이즈를 하나 변경시에 관련된 다른 페이지의 모든 것들을 하나하나 수정해야하기 때문이다.
그래서 모든 페이지에서 공통적으로 사용할 스타일들을 common.css파일에 작성해두었다. 그리고 모든 html파일에 해당 파일을 연결시켜줬다. 이로인해 유지보수를 하는데 효율성이 매우 상승하였다!
common.css
내가 작성했던 스타일 코드들을 기능별로 나누어 설명하고자 한다.
나는 해당 파일에 내가 설정한 css 속성, 기본 설정, button, card, header, footer, 그 외의 내용을 작성했다.
common.css에 작성했던 것 중에 header와 footer의 스타일은 저번 글에 작성하였으므로 제외하고 작성하겠다.
사용자 지정 css 속성
사용자 지정 속성(css 변수, 종속 변수)은 내가 직접 정의한 개체를 의미한다. 현재 진행중인 프로젝트에서 전반적으로 재사용할 값들을 담을 때 주로 사용한다. 표기법과 사용법은 다음과 같다.
:root {
--inq-blue: #0088BD;
--inq-yellow: #FFD303;
--inq-white: #f4fbff;
--font-black: #1f1e1e;
--recruit-color: #FC8B79;
--execution-color:#FFD303;
--complete-color: #A1ED85;
--title-font: 80px;
--sub-title-font: 50px;
--large-font: 40px;
--mideum-font: 32px;
--small-font: 20px;
--btn-font: 30px
}
- 표기법 :root
/* 표기법 */
:root {
--main-color: #FC8B79;
--sub-color: #0088BD;
--main-font: 60px;
}
:root{--변수명: 값;}
형태로 작성한다. 이렇게 작성하면 나중에 색상이나 전반적인 글자 크기를 수정할 때 해당 파일에서 값 하나만 바꿔주면 모든 파일에서 해당 값들이 변경된다. 이로인해 수정할 때 오류없이 간단하게 바꿀 수 있다.
그리고 이렇게 속성을 지정하면 해당 값들이 의미하는 것이 무엇인지 직관적으로 알 수 있어서 이해하기 좋다. 그저 색상을 #0088BD로 적는 것 보다 –sub-color로 작성했을 때가 해당 속성이 의미하는 것이 무엇인지 한번에 이해가 가능하다는 장점이 있다.
- 사용법 var()
/* 사용법 */
p {
color: var(--main-color);
font-size: var(--main-font);
}
지정한 속성을 사용할때는 꼭 var()
안에 넣어 사용해야 한다.
var() 함수안에 넣어 사용해야 사용자가 지정한 속성이라는 것을 인식해서 제대로 코드가 작동할 수 있게 된다.
기본 설정
공통적으로 자주 사용하는 태그들의 기본 속성들을 내가 원하는 스타일로 설정했다. 해당 태그를 사용할때마다 속성을 변경하기에는 효율성이 떨어지니 common 스타일 파일에 작성하였다. 덕분에 매번 속성을 변경해야하는 번거로움을 줄일 수 있었다.
/* COMMON */
body {
color: var(--font-black);
font-size: var(--mideum-font);
font-weight: 400;
line-height: 1.4; /*글자의 행간을 줌 (줄높이)*/
font-family: 'Noto Sans KR', sans-serif;
}
img {
display: block;
/* 이제 이미지는 더이상 인라인 요소가 아닌 블럭요소가 된다 */
}
a {
/* 모든 a태그의 밑줄을 없애기 */
text-decoration: none;
color: var(--font-black);
}
a:hover {
text-decoration: none;
color: var(--font-black);
}
input,
select {
font-size: var(--mideum-font);
}
.inner {
width: 720px;
margin: 0 auto;
position: relative; /* 자식요소 때문에 position값을 넣는 것이기에 문제가 되지 않기 위해 relative로 함 */
}
- body
따로 속성을 부여하지 않은 것에는 해당 속성들이 적용된다.
- img
img태그는 인라인 요소이다. 나는 img 태그를 사용할때 블럭처럼 사용하고 싶었기 때문에 display:block;
을 사용하여 블럭요소로 변경하였다.
- a
a태그 사용시 파란 색상과 밑줄이 발생한다. 해당 요소를 없애고 싶어 위와같이 색상을 검정색으로 변경했다.
밑줄을 없애기 위해서 text-decoration: none;
을 사용하였다. 밑줄을 없앤다(none)는 의미이다.
- a:hover
a태그에 hover를 하고 나면 색상과 밑줄이 발생하였기 때문에
마우스를 올린 것만이 아닌 a태그를 클릭하고 나면 방문했다는 것을 나타내기 위해 색상이 변경되고 밑줄이 발생하는 것
a태그와 동일하게 속성을 작성했다.
- input,select
input과 select요소를 사용할때마다 해당 파일에 글자 크기를 변경하는 번거로움을 줄이기 위해서 common 스타일 파일에 글자 크기를 정의하였다.
- .inner
inner 클래스는 내가 만들 클래스이다.
페이지를 만들 때 내용들을 꽉차게 넣는 것이 아닌 양쪽에 수직으로 여백을 넣어주는 것을 흔히 볼 수 있다. 그렇게 하기 위해 내용을 넣을 부분의 너비 사이즈를 정해준 것이다. width: 720px;
그리고 가운데 정렬을 위해 margin: 0 auto;
를 작성하였다.
position: relative;
는 다른 속성들이 부모요소를 기준으로 위치를 조정할 때가 빈번히 발생하게 되는데 그때 대부분 부모요소가 해당 inner이 된다. 그대마다 매번 작성하기 번거로우니 common 파일에 정의해두었다.
버튼 css
모든 페이지에서 버튼은 굉장히 많이 사용한다. 버튼의 스타일이 대부분 동일하고 약간의 색상 변화를 주는 경우가 대다수였기에 common 파일에 버튼 스타일을 정의해두어 각 페이지에서 사용할때마다 해당 클래스명만을 입력하여 버튼 스타일을 사용하였다.
/* Button */
.bton {
width: 250px;
padding: 10px;
border-radius: 4px;
color: var(--font-black);
background-color: transparent;
font-size: var(--btn-font);
font-weight: 500;
text-align: center; /*박스 안에서 글자 가운데 정렬*/
cursor: pointer;
/* box-sizing: border-box; 패딩, 보더가 들어간 만큼 요소가 커지지 않도록 */
display: block; /* a나 span태그에 버튼 클래스를 부여했을 때도 버튼이 정상적으로 나오도록 */
transition: .4s; /* hover시 자연스럽게 색상이 바뀌도록 */
}
.bton:hover {
background-color: var(--inq-yellow);
}
.bton.btn--reverse {
background-color: var(--inq-yellow);
border: 0;
color: white;
}
.bton.btn--reverse:hover {
background-color: #ffa703;
}
.bton.btn--blue {
background-color: transparent;
border: 2px solid var(--inq-blue);
border-radius: 4px;
color: var(--inq-blue);
}
.bton.btn--blue:hover {
background-color: var(--inq-blue);
color: var(--inq-white);
}
.bton.btn--blue-reverse {
background-color: var(--inq-blue);
border: 2px solid var(--inq-blue);
border-radius: 4px;
color: var(--inq-white);
}
.bton.btn--blue-reverse:hover {
background-color: transparent;
color: var(--inq-blue);
}
- bton
가장 기본적인 버튼 스타일 속성이다. 해당 클래스명을 작성하면 내가 작성한 기본적인 버튼 속성이 적용된다.
- CSS선택자: 일치 선택자
선택자 ABC와 XYZ를 동시에 만족하는 요소를 선택할 때 사용한다.
<div class="abc xyz">hello</div>
<span class="ght">world</span>
.abc.xyz {
color: red;
}
span.ght {
color: blue;
}
위의 경우에는 hello는 빨간색, world는 파란색으로 결과가 나온다.
나는 일치 선택자를 기본적으로 적용한 버튼 스타일 속성에서 추가적으로 변경하고 싶은 속성이 있을 때 사용하였다.
예를 들어,.bton에서 글자 색상만을 바꾸고 싶을 때, 배경 색상을 변경하고 싶을 때 등등
- background: transparent
background: transparend
를 사용하여 배경색상을 투명하게 만든다.
- transition: 속성명 지속시간 타이밍함수 대기시간;
transition: .6s
요소의 전환(시작과 끝)효과를 지정하는 단축 속성이다. 이때, 지속시간은 필수적으로 작성해야 하는 속성이다.
지속시간을 입력하면 전환 효과의 시간을 지정한다. 기본은 0s로 전환 효과가 없다. 지속시간을 작성할때는 원하는 시간 뒤에 S를 붙혀 작성한다. 이때 S는 second를 의미한다.
만약 0.5초 지속시간을 주고 싶다면 앞의 0은 생략이 가능하다. (0.5s -> .5s)
카드 Card
홈 화면과, 프로젝트 홈 화면에서 사용하는 카드에 대한 스타일을 common 파일에 작성하였다. 아직은 두 페이지에서만 사용하지만 차후 업데이트를 하게 된다면 다른 곳에서 사용가능성이 높기 때문이다. 또, 두 페이지에서 사용하는 카드의 모양이 완전히 동일하기 때문에 각 페이지의 css파일에 작성하는 것 보다는 common 파일에 작성하는 것이 더 수정에 편리할 것이라 생각이 들어 common 파일에 작성하였다.

- HTML
<a href="#" onclick="location.href='./project/project_info.html'" class="card swiper-slide">
<img class="card-img-top" src="./images/inq_logo.png" alt="Card image cap" />
<div class="card-body">
<div class="card-text card-title">[인큐] 프로젝트 관리 매니저</div>
<div class="card-text">
<div class="card-info">
<div class="info-left">
<div class="info-date">
모집기간
<span class="recruit-date">22.05.10 - 22.05.20</span>
</div>
</div>
<div class="info-right">
<div class="info-member">
<span class="symbol material-icons">person</span>
<span class="member-personnel">
2
/
5
</span>
</div>
<div class="info-progress recruit">모집중</div>
</div>
</div>
</div>
</div>
</a>
- 카드 구조
카드의 구조는 크게 img, card-title, info-right, info-left로 나눌 수 있다.
img는 사용자가 등록하는 프로젝트의 이미지이다.
card-title은 등록한 프로젝트의 이름이다.
info는 두개로 나뉘어 info-right, info-left인데, info-right에는 모집기간, info-left에는 모집중인 인원과 참여 인원, 모집 상태가 나온다.
- CSS
/* Card */
.card {
width: 600px;
padding: 50px;
/* border: 3px solid var(--inq-blue); */
box-shadow: rgba(17, 17, 26, 0.05) 0px 1px 0px, rgba(17, 17, 26, 0.1) 0px 0px 8px;
}
.card .card-body {
margin-top: 50px;
}
.card .card-body .card-text.card-title {
font-weight: 700;
font-size: var(--large-font);
}
.card .card-body .card-text .card-info .info-left {
margin:20px 0 20px 0;
}
.card .card-body .card-text .card-info .info-right {
display: flex;
}
.card .card-body .card-text .card-info .info-right .info-member {
display: flex;
}
.card .card-body .card-text .card-info .info-right .info-member .symbol {
font-size: 50px;
color: #5b5b5b;
}
.card .card-body .card-text .card-info .info-right .info-member .member-personnel {
margin-top: 7px;
margin-left: 15px;
}
.card .card-body .card-text .card-info .info-right .info-progress {
width: auto;
border-radius: 8px;
padding: 10px;
margin-left: 150px;
}
/* 모집중 */
.card .card-body .card-text .card-info .info-right .info-progress.recruit {
background-color: var(--recruit-color);
}
/* 진행중 */
.card .card-body .card-text .card-info .info-right .info-progress.execution {
background-color: var(--inq-yellow);
}
/* 완료 */
.card .card-body .card-text .card-info .info-right .info-progress.complete {
background-color: var(--complete-color);
}
- 모집상태 표시
카드에는 해당 프로젝트의 모집상태가 나오게 되는데 모집중, 진행중, 완료 3가지이다. 모집상태에 따라 색상이 다르게 나온다.
모집중은 빨강, 진행중은 노랑, 완료는 초록이다. 상태표시 색상은 신호등을 착안하여 정했다.
- box-shadow
카드 테두리에 그림자를 주었다. 내가 직접 설정해서 하기에는 이쁘게 만들기가 힘들었다. 그래서 서칭을 통해 다양한 box-shadow를 정리해둔
box-shadow 사이트를 찾았다.
언더라인 underline
홈 페이지와 프로젝트 홈 페이지에 적용되는 언더라인이 있다.
홈 페이지에서는 프로젝트 홈 페이지로 이동하는 버튼에서 프로젝트클릭시 언더라인이 나타나면서 이동한다.
프로젝트 홈 페이지에서는 검색을 할 때 모집중, 진행중, 완료를 선택한 후 검색을 할 수 있다. 이때, 프로젝트의 상태를 어떤 것을 선택했는지 나타내줄 때 언더라인을 사용한다.

- HTML
사용하고자 하는 부분의 클래스에 underline을 작성한다.
<div class="text-title">
<a href="#" onClick="location.href='../project/project_home.html'" class="title title-cursor underline line" title="프로젝트 페이지로 이동">프로젝트</a>
</div>
- CSS
/* Underline */
.underline {
background-repeat: no-repeat;
background-size: 0% 100%;
background-image: linear-gradient(transparent 60%, var(--inq-yellow) 40%);
}
.underline:hover {
background-size: 100% 100%;
}
.underline.click-line {
background-size: 100% 100%;
}
- background: linear-gradient();
linear-gradient(방향 또는 각도, 색상과 정지 지점 … )
두개의 색상이 직선을 따라 점진적으로 색상이 변경되게 해준다.
내가 작성한 background-image: linear-gradient(transparent 60%, var(--inq-yellow) 40%);
은, 투명 배경을 화면의 60%, 노란색 (–inq-yellow)을 40%로 설정했다.
이렇게 %로 원하는 화면의 비율을 설정할 수도 있다.
방향(각도)를 줌으로 자연스럽게 색상이 섞이게 하고 색상이 변경되는 방향도 설정할 수 있다.
background-image: linear-gradient(90deg, red 20% ,yellow 80%)
해당 코드는 색상이 변경되는 각도는 90도(오른쪽) 빨강은 20%, 노랑은 80% 차지한다.
- background-size
요소의 배경 이미지의 크기를 설정한다. 그대로 두거나, 늘리거나 줄이는 등을 할 수 있다. 배경 이미지로 덮히지 않는 부분은 background-color
속성으로 채워지며, 배경 이미지가 투명, 반투명해도 background-color 색상이 보인다.
background-size는 키워드값, 단일값, 두개값, 다중배경, 전역값이 있다. 이중에서 내가 사용한 것은 두개값이다.
background-size: 0% 100%;
의 첫번째 값은 너비, 두번째 값은 높이를 설정한다.
hover와 click을 하지 않았을 때는 아무것도 없다. (너비 0% 높이 100%) 해당 언더라인 부분에 마우스를 올리거나 클릭했을때는 너비가 100%이 되면서 linear-gradient 속성이 보이게 된다.
- JS
$('.underline').each(function(index){
$(this).attr('underline-index', index);
}).click(function(){
/*클릭된 <div>의 underline-index 값을 index 변수에 할당한다.*/
var index = $(this).attr('underline-index');
/*클릭한 <div>에 click-line 클래스 추가*/
$('.underline[underline-index=' + index + ']').addClass('click-line');
/*그 외 <div>는 click-line 클래스 삭제*/
$('.underline[underline-index!=' + index + ']').removeClass('click-line');
});
- attr()
attr()은 jQuery의 메소드이다. 선택자에 의해 선택된 요소중에서 가장 처음의 요소의 속성값을 가져온다.(즉 원하는 것을 찾는 애랄까?)
.attr(attributeName): 선택된 요소 집합에서 첫번째 요소의 attributeName에 해당하는 속성값을 가져온다.
.attr(attributeName, Value): 선택자에 의해 선택된 요소에 하나 이상의 속성을 부여할 수 있다.
$(this).attr('underline-index', index);
는 underline-index에 index를 부여했다.
attr() 참고 글
- addClass와 removeClass
jQuery의 메소드로, 원하는 클래스를 추가하거나 삭제할 수 있다.
나는 underline 클릭하면 click-line 클래스를 추가하여 linear-gradient가 적용되게, 클릭하지 않으면 click-line 클랙스를 삭제하게 하였다.
마무리
여러 파일에서 공통적으로 사용하는 것들을 잘 작성해야 계속 페이지를 구축하면서 귀찮은 일들을 줄일 수 있다는 것을 온몸으로 깨달았다.
어느 글에서 개발자들이 제일 귀차니즘이 심하다는 글을 봤었는데 맞는 것 같다. 나중에 귀찮지 않기 위해서 간단하지만 최대의 효율을 만들기 위해 머리를 쥐어 짠달까… 난 아직 한참 멀어서 온몸을 지배하는 귀차니즘을 이길 정도의 실력이 없지만, 나중에 점점 실력이 늘어나서 뚝딱뚝딱 만들고 싶다..!!
로그인 페이지
해당 프로젝트는 로그인을 해야만 이용이 가능하게 만들었다.
그래서 해당 프로젝트에 들어가면 가장 먼저 보이는 것은 로그인 페이지이다.
로그인 페이지는 여타 그렇듯 아이디, 비밀번호 입력창과 로그인, 회원가입 버튼을 넣었다. 아이디와 비밀번호 찾기는 구현하지 못하여서 형태만 넣어 두었다.

로그인 HTML
<!-- Login -->
<section class="login">
<div class="inner">
<div class="text-title">
<span class="title">로그인</span>
</div>
<form action="">
<div class="text-body">
<div class="row">
<label for="loginId" class="sub-title">아이디</label>
<input type="text" id="loginId" name="loginId" required
minlength="4" maxlength="15">
</div>
<div class="row">
<label for="loginPw" class="sub-title">비밀번호</label>
<input type="password" id="loginPw" name="loginPw" minlength="8" required>
</div>
<div class="find-member">
<a href="javascript:void(0)" class="find-account">아이디 찾기</a>
<a href="javascript:void(0)" class="find-account">비밀번호 찾기</a>
</div>
<div class="btn-group">
<div class="btn-row">
<a href="#">
<input class="bton btn--reverse" type="button" value="로그인하기">
</a>
</div>
<div class="btn-row">
<!-- 회원가입 페이지 링크 연결하기 -->
<a href="#">
<button class="bton btn--blue" onClick="location.href='../member/signup.html'" type="button">
회원 가입하기</button>
</a>
</div>
</div>
</div>
</form>
</div>
</section>
- section을 만들어 login 클래스명을 부여하였다.
클래스 inner은 스타일을 위해 정의해둔 것으로 추후 common파일 글에 설명하도록 하겠다.
- 로그인 페이지라는 것을 알려주기 위한 타이틀
- 입력받은 데이터를 전송해야 하기 때문에 form 태그를 사용한다.
입력받을 모든 데이터들은 로그인 버튼을 클릭과 동시에 데이터베이스로 전송된다.
- text-body: 입력될 데이터들을 묶는 박스를 만들어 스타일을 정의하기 쉽게 한다. (다른 페이지에서도 비슷한 용도로 사용 될 예정)
- row (열): 아이디, 비밀번호 입력창의 스타일은 동일하기 때문에 중복성을 최소화 하고자 동일한 클래스명을 부여하였다.
- 아이디: 입력받는 타입은 text, 백엔드로 넘길 id와 name. 최소 4글자 입력, 최대 15글자 입력 가능. required 속성을 통해 필수적으로 입력을 하도록 했다.
- 비밀번호: 입력받는 타입은 password. 최소 8글자, 최대 15글자 입력하도록 하였다. required 속성을 부여하여 필수 입력을 하도록 했다.
- label 과 input 태그
- label
사용자 인터페이스 항목을 설명한다.
input 요소와 연결하면 label 클릭시 input에 초점을 맞추거나 활성화 시킬 수 있다. 또, 폼 입력에서 label을 읽어 보조 기술 사용자가 입력해야 하는 텍스트가 무엇인지 쉽게 이해할 수 있도록 한다. (출처: MDN 웹문서)
- input
사용자의 데이터를 받을 수 있는 대화형 컨트롤을 생성한다. 다양한 유형으로 데이터를 입력받을 수 있다.
- find-member 클래스: 형태만 존재하게 하였다.
- button
btn-group으로 회원가입과 로그인 버튼을 묶었다.
btn-row로 각 버튼들의 스타일을 부여하도록 했다.
- 로그인 버튼
로그인 버튼을 클릭하면 입력한 데이터들을 백엔드로 넘기면서 로그인이 완료되어야 하기에 input 태그로 값을 보냈다.
- 회원가입 버튼
회원가입 버튼 클릭시 회원가입 페이지로 이동하게 만들었다.
button 태그를 사용했으며, onClick 속성을 통해 html에서 페이지를 옮길 수 있도록 했다.
- onClick=”이동하고자 하는 페이지의 로컬 주소”
<button class="bton btn--blue" onClick="location.href='../member/signup.html'" type="button">회원 가입하기</button>
로그인 CSS
/* Login */
.login {
margin-top: 300px;
margin-bottom: 500px;
}
.login .inner {
color: var(--inq-blue);
}
.login .text-title {
margin-bottom: 80px;
}
.login .text-title .title {
font-size: var(--large-font);
font-weight: 800;
}
.login .text-body {
margin: 0 auto;
position: relative;
}
.login .text-body .row {
display: flex;
flex-direction: column;
margin: 40px 0;
}
.login .text-body .row input {
width: 720px;
height: 82px;
padding-left: 30px;
border: 2px solid var(--inq-blue);
color: var(--inq-blue);
}
.login .text-body .row .sub-title {
margin-bottom: 18px ;
}
.login .text-body .find-member {
position: absolute;
width: 720px;
right: 0;
left: 0;
margin: auto;
padding-left: 150px;
}
.login .text-body .find-member a {
color: var(--inq-blue);
}
.login .text-body .find-member .find-account {
margin-left: 30px;
}
.login .text-body .btn-group {
position: absolute;
width: 720px;
right: 0;
left: 0;
margin: auto;
margin-top: 50px;
padding-left: 165px;
}
.login .text-body .btn-group .btn-row {
margin: 50px 0;
}
.login .text-body .btn-group button,
.login .text-body .btn-group input {
width: 390px;
height: 82px;
}
- 버튼 hover시 색상이 변경되는데, 이에 대한 스타일은 모두 common 스타일 파일에 공통적으로 정의를 해두었기에 해당 login 스타일에는 없다.
- 로그인 페이지 css는 사이즈 조정이라던가 크기 조정이 대부분이다.
- 입력창 글자 색과 테두리 색 변경하기
해당하는 클래스에 color:blue; border: blue;
를 적용하면 글자색과 테두리 색을 원하는 색상으로 변경이 가능하다! -> 이번에 처음 알게 되었다.
회원가입 페이지
회원가입 페이지를 만들 때, 로그인 페이지에서 사용한 구조와 스타일을 그대로 가져와서 사용하면 됐었기에 어려운 점은 크게 없었다.
하지만, 내가 전혀. 단 한번도 해본 적 없었던 모달 창을 만드느라 이거 하나에 굉장히 많은 시간을 썼다. 한… 이틀 정도…?ㅎ
처음 모달창 만들 던날, 아무리 잘 입력해도 작동을 하지 않아서.. 때려치고 다른 것을 했다. 다른 날 다른 참고 자료를 보고 계속 도전한 끝에 겨우 성공해서…!!! 해당 프로젝트에서 모달창을 매우 잘 사용할 수 있었다.
언제나 깨닫는 것은 한 번 잘 만들어 두면 두고두고 나중에 쉽게 써먹을 수 있다는 것이다.

회원가입 페이지1

회원가입 페이지2

회원가입 페이지 모달창
회원가입 HTML
로그인 페이지의 구조와 동일한 부분들은 지워두었다.
select 태그 사용하는 것과 modal창 구조만 남겨두었다.
모달창을 오로지 내가 짠 코드로만 완성하고 싶었는데 도전했다가 실패하고.. 마감 기간은 찾아오기에 결국 bootstrap을 사용하여 모달창을 구현하였다.
<!-- Sign up -->
<section class="signup">
<div class="inner">
<div class="text-title">
<span class="title">회원 가입</span>
</div>
<form action="" method="get" class="form-example">
<div class="text-body">
<div class="row">
<label for="memberPosition" class="sub-title">포지션*</label>
<select name="memberPosition" id="memberPosition" required >
<option value="">--- Postion ---</option>
<option value="fullstack">Full Stack</option>
<option value="backend">Backend</option>
<option value="frontend">Frontend</option>
<option value="ios">IOS</option>
<option value="android">Android</option>
<option value="ai">AI</option>
<option value="null">Null</option>
</select>
</div>
<div class="row">
<label for="memberSkill" class="sub-title">보유기술*</label>
<div class="modal-btn">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary bton btn--blue-reverse" data-toggle="modal" data-target="#exampleModalCenter">
선택하기
</button>
</div>
<!-- Modal -->
<div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">보유기술</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="check-box">
<input type="checkbox" id="HTML" name="HTML">
<label for="HTML">HTML</label>
</div>
<div class="check-box">
<input type="checkbox" id="CSS" name="CSS">
<label for="CSS">CSS</label>
</div>
<div class="check-box">
<input type="checkbox" id="JS" name="JS">
<label for="JS">JS</label>
</div>
<div class="check-box">
<input type="checkbox" id="Spring" name="Spring">
<label for="Spring">Spring</label>
</div>
<div class="check-box">
<input type="checkbox" id="Django" name="Django">
<label for="Django">Django</label>
</div>
<div class="check-box">
<input type="checkbox" id="Vue.js" name="Vue.js">
<label for="Vue.js">Vue.js</label>
</div>
<div class="check-box">
<input type="checkbox" id="Angular" name="Angular">
<label for="Angular">Angular</label>
</div>
<div class="check-box">
<input type="checkbox" id="Swift" name="Swift">
<label for="Swift">Swift</label>
</div>
<div class="check-box">
<input type="checkbox" id="Kotlin" name="Kotlin">
<label for="Kotlin">Kotlin</label>
</div>
<div class="check-box">
<input type="checkbox" id="jQuery" name="jQuery">
<label for="jQuery">jQuery</label>
</div>
<div class="check-box">
<input type="checkbox" id="Express" name="Express">
<label for="Express">Express</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary bton btn--reverse" data-dismiss="modal">완료</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
회원가입 CSS
회원가입 페이지의 CSS는 크게 특징적인 것은 없다.
/* Modal */
.signup .text-body .row .modal-btn .btn {
width: 250px;
padding: 10px;
font-size: var(--btn-font);
}
.signup .text-body .row .modal-dialog.modal-dialog-centered .modal-content .modal-header h5 {
padding: 12px;
font-weight: 700;
font-size: var(--large-font);
}
.signup .text-body .row .modal-dialog.modal-dialog-centered .modal-content .modal-header button span {
font-size: 45px;
}
.signup .text-body .row .modal-dialog.modal-dialog-centered .modal-content .modal-body {
display: flex;
flex-wrap: wrap;
}
.signup .text-body .row .modal-dialog.modal-dialog-centered .modal-content .modal-body .check-box input {
width: 40px;
height: 40px;
margin: 30px 8px 25px 30px;
}
모달창 css에서 약간 애 먹은 것은 checkbox 사이즈와 정렬이 내가 생각한 것 처럼 잘 안되서 시간이 좀 걸렸다.
checkbox와 그 옆의 label의 사이즈랑 위치가 동일 선상에 맞추느라 힘들었다… 각각 사이즈를 다르게 해서 맞추었다.
마무리
로그인과 회원가입 페이지는 유사해서 금방 만들 수 있었다.
다만, 회원가입 페이지에서 모달창이 ^^… 처음 적용해보고 만들어보겠다고 낑낑거리다가 시간이 많이 지체되었지만..! 어찌저찌 완성은 했으니 만족한다!
다음은 가장 큰 난제였던 메인 홈 화면 제작기를 작성하도록 하겠다 :)
여는 말
이 프로젝트를 완성한 것은 2021년 11월 말인데…ㅎ;; 이제야 프로젝트 완성했던 글을 쓴다…
사실, 이 프로젝트를 통해 새롭게 알게 된 내용 정리하고 그래야 하는데, 너무 오래 지났다보니 정확하게 새롭게 배웠던 내용이 뭐 였는지 기억이 안난다…!!
~~사실 새롭게 알게 된 내용이 많기도 했고
결론은, 게으름 피운 나의 업보..랄까…? 일단 (나름)최근에 끝냈던 동아리 프로젝트 관련 내용이 기억날때 다 적어둬야 겠다고 판단했다. 그래도 이 프로젝트의 완성본과 약간 기억나는 점들을 작성하자는 생각에 다시 이 프로젝트 관련 글을 작성한다!
결과물
지도

21년도 11월에 완성하고 서버를 열어뒀는데 22년 2월즈음, 혹시 서버 비용 나올까봐 닫아주면서… 지도 API연결된게 요롷게 사라졌다. 2월에는 멀쩡했는데, 최근에 사진이라도 남기자 생각해서 로컬 서버를 열어서 보니 연결이 끊긴 걸 확인했다. 아마 새롭게 업데이트가 되서 더이상 안되는 걸지도…? 사실 백엔드는 잘 모른다
- 기능
지도의 기능은 다음과 같다.
포스트를 작성할 때 지도에서 위치를 선택한다. 그러면 자동으로 위도와 경도로 변환되어 작성된다. (위도와 경도는 데이터베이스로 넘어간다.)
포스트를 포스팅하면 해당 글의 위도와 경도가 지도에 마커로 표시된다.
해당 표시로 인해, 그간 내가 어디를 여행다니고 기록을 남겼는 지 한 눈에 알 수 있어서 좋다.
- TIL
지도 API를 불러오는 것, 마커 찍는 방법, 지도의 기본 위치를 설정 등 지도를 활용하는 백엔드 기술을 배울 수 있었다.
구글에서 무료로 배포하는 지도 API를 활용하는 법 (구글에서 친절하게 예시와 함께 설명을 해두었다. 영어로 되어있는게 함정)
- 구글 지도 API 링크
<!-- Google Map -->
<script
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAlc1cmKgefcHGoKjAL5FUUjXGrAlRvwN0&callback=initMap&v=weekly"
async></script>
<script src="https://unpkg.com/@google/markerclustererplus@4.0.1/dist/markerclustererplus.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/exif-js"></script>
- 지도 API 연결하기
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: {lat: 37.5642135, lng: 127.0016985},
zoom: 8,
});
}
- 지도에 마커 찍기
function showArticles() {
$.ajax({
type: "GET",
url: "/trip",
data: {},
success: function (response) {
const articles = response["articles"];
console.log(articles);
for (let i = 0; i < articles.length; i++) {
// 마커 지도에 저장하기
let marker = new google.maps.Marker({
map: map,
position: {
lat: Number(articles[i]['lat']),
lng: Number(articles[i]['lng']),
}
});
makeCard(articles[i]["writer"], articles[i]["img"], articles[i]["date"], articles[i]["place"], articles[i]["content"]);
}
}
})
}
- 솔직히 말하자면 정확히 어떻게 사용했는지 지금은 잘 기억이 안나긴 한다. 하지만 다음번에 다시 할때는 조금 더 수월하게 할 수 있을 것 같다!
이거 처음 만들때는 멘토님 계셨어도 며칠동안 했던 것 같다..
포스팅

- 기능
상단 Trip버튼 클릭시 포스팅 상자가 열린다.
포스팅 상자 안 작성자,여행날짜,여행장소,사진업로드,내용 을 작성하면 된다. 위도와 경도는 여행장소 선택시 자동으로 입력이 된다.
모든 내용 작성 완료 후 저장버튼을 누르면 팝업창으로 작성 완료가 뜨면서 포스트가 업로드 된다.
- TIL
- 포스팅 박스 열고 닫기
function openClose() {
// id 값 post-box의 display 값이 block 이면
if ($('#posting-box').css('display') === 'block') {
// post-box를 가리고
$('#posting-box').hide();
} else {
// 아니면 post-box를 보여주기
$('#posting-box').show();
}
}
- 여행장소
여행장소 검색하는 것과 검색한 것을 위도, 경도로 바뀌게 하는 작업을 했었다. 여행장소를 검색하면 상단 지도에서 위치가 옮겨지고 위도, 경도가 입력된다.
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: {lat: 37.5642135, lng: 127.0016985},
zoom: 8,
});
let geocoder = new google.maps.Geocoder();
document.getElementById('geo-submit').addEventListener('click', function () {
// 여기서 실행
geocodeAddress(geocoder, map);
});
/**
* geocodeAddress
*
* 입력한 주소로 맵의 좌표를 바꾼다.
*/
function geocodeAddress(geocoder, resultMap) {
// 주소 설정
let address = document.getElementById("post-trip-place").value;
/**
* 입력받은 주소로 좌표에 맵 마커를 찍는다.
* 1번째 파라미터 : 주소 등 여러가지.
* ㄴ 참고 : https://developers.google.com/maps/documentation/javascript/geocoding#GeocodingRequests
*
* 2번째 파라미터의 함수
* ㄴ result : 결과값
* ㄴ status : 상태. OK가 나오면 정상.
*/
geocoder.geocode({'address': address}, function (result, status) {
if (status === 'OK') {
// 맵의 중심 좌표를 설정한다.
resultMap.setCenter(result[0].geometry.location);
// 맵의 확대 정도를 설정한다.
resultMap.setZoom(18);
// 맵 마커
let marker = new google.maps.Marker({
map: resultMap,
position: result[0].geometry.location
});
tot.location = {lat: marker.getPosition().lat(), lng: marker.getPosition().lng()}
$('#post-trip-location').val(tot.location.lat + '/' + tot.location.lng);
// // 위도
// latitude = marker.position.lat();
// // 경도
// longitude = marker.position.lng();
} else {
alert('지오코드가 다음의 이유로 성공하지 못했습니다 : ' + status);
}
});
}
}
- 사진 업로드
파일 선택 버튼을 클릭하면 본인 파일에서 원하는 사진을 선택하여 업로드 할 수 있다. 처음하는 작업이라 엄청나게 서칭한 끝에 성공할 수 있었다… 너무 어려웠다..ㅜ
function uploadImage() {
let images = $('#post-img')[0].files[0]
if (images === undefined) {
alert('이미지를 선택해주세요.')
return
}
let formData = new FormData();
formData.append("images", images)
$.ajax({
type: "POST",
url: "/image",
processData: false,
contentType: false,
data: formData,
success: function (res) {
if (res['result'] === 'success') {
img_path = res['img_path']
alert('사진 업로드 성공!')
console.log(img_path);
} else {
alert('사진 업로드 실패!')
console.error(res['error'])
}
}
})
}
- 포스팅 하기
저장 버튼 클릭시 포스팅이 완료 된다! 백엔드는 완전 처음이었기 때문에 다양한 데이터들을 데이터베이스로 넘기고 빼와서 포스트 보이게 하기 쉽지 않았다.
function postArticle() {
const writer = $("#post-writer").val();
const date = $("#post-trip-date").val();
const place = $("#post-trip-place").val();
const content = $("#post-trip-content").val();
// POST 방식으로 카드 생성 요청하기
$.ajax({
type: "POST", // POST 방식으로 요청하겠다.
url: "/trip", // /memo라는 url에 요청하겠다.
data: {
writer_give: writer,
date_give: date,
place_give: place,
lat_give: tot.location.lat,
lng_give: tot.location.lng,
img_give: img_path,
content_give: content
}, // 데이터를 주는 방법
success: function (response) { // 성공하면
if (response["result"] === "success") {
alert("포스팅 성공!");
// 3. 성공 시 페이지 새로고침하기
window.location.reload();
} else {
alert("서버 오류!");
}
}
})
}
카드

포스팅 버튼에서 저장을 누른 후 해당 카드 모양으로 게시된다.
- 기능
최상단에 작성자 이름이 나오고 그 이후로 업로드한 사진, 여행날짜, 여행 장소, 내용이 나온다.
카드에 margin을 주었으며, 웹 사이즈에 따라 카드가 초과되면 다음 줄로 내려가게 flex-wrap: wrap설정을 하였다.
- TIL
- JavaScript
function makeCard(writer, img, date, place, content) {
const tempHtml = `<div class="cards-box">
<div class="card">
<span class="card-writer">Writer ${writer}</span>
<img class="card-img" src="${img}">
<span class="card-trip-date">여행 날짜: ${date}</span>
<span class="card-trip-place">여행 장소: ${place}</span>
<span class="card-trip-content">${content}</span>
</div>
</div>`;
$("#card-bundle").append(tempHtml);
}
function getImage() {
$.ajax({
type: 'GET',
url: '/trip',
success: function (res) {
let images = res['images']
for (let i = 0; i < images.length; i++) {
let image = images[i]
console.log(image)
let temp = `<img src="${image}" alt="image${i}">`
$('.card-img').append(temp)
}
}
})
}
- Django
@app.route('/trip', methods=['POST'])
def post_article():
# 클라이언트로부터 데이터를 받기
writer_receive = request.form['writer_give']
date_receive = request.form['date_give']
place_receive = request.form['place_give']
lat_receive = request.form['lat_give']
lng_receive = request.form['lng_give']
img_receive = request.form['img_give']
content_receive = request.form['content_give']
article = {'writer': writer_receive, 'date': date_receive, 'place': place_receive,
'lat': lat_receive, 'lng': lng_receive, 'img': img_receive, 'content': content_receive}
# mongoDB에 데이터를 넣기
db.trip.insert_one(article)
# 성공 여부 & 성공 메시지 반환하기
return jsonify({'result': 'success'})
글 작성을 마치며
굉장히 오랜만에 만들었던 파일을 보면서 기억이 새록새록 떠오른다. 당시에 백엔드 너무 어려웠어서 정말 힘들고 고통받았던… 기억이 있는데. 지금 와서 다시 보니 그래도 그간 참고 열심히 하길 잘했다는 생각이 든다.
처음 배우면서 프로젝트를 진행해서 너무 복잡하고 어떤 순서로 해야 할 지 감이 안 잡혔었는데, 지금 다시 보니 뭔가 좀 알겠는 느낌? (이 프로젝트를 만들 던 당시보다는 머리에 든게 많아져서 그런가 보다. 뿌듯-)
지금 이 글의 내용은 거의 자바스크립트 위주로 작성했지만 Django를 하면서도 새롭게 안 것도 많다. 근데, 이걸 다 넣고 그러기엔 좀 애매하달까…? 그래서 마지막 카드 부분에만 작성하였다.
내가 앞으로 백엔드를 할 일이 있을 지는 모르겠지만, 이 프로젝트 경험 덕분에 백엔드는 어떻게 돌아가는지 이해가 많이 되었다. 역시 글로 읽었을 때와 직접 경험했을 때는 매우 다르달까.
나중에 기회가 된다면, 해당 프로젝트를 참고하여 백엔드를 해보는 걸로! TOT 프로젝트 글 작성 끝!
내가 가장 먼저 만든 것은 역시 Header이다.
헤더 좌측에는 동아리 로고를 넣었고, 우측에는 회원 이름 (비 로그인시, 로그인하기 버튼)을 나오게 하였다.
동아리 로고를 클릭하면 메인 홈 화면으로 이동하도록 링크를 걸어 두었다. 우측 로그인 혹은 회원이름에 마우스를 hover하면 노란 박스 배경이 생긴다. 비 로그인시에 로그인 버튼을 클릭하면 로그인 화면으로 넘어간다. 회원 이름일때에 클릭하면 홈 화면으로 넘어간다. (홈 화면에 회원 정보가 있기 때문이다.)

헤더는 로그인과 비로그인 상태 두가지가 존재하기 때문에 파일을 두개로 만들었다.
로그인 상태일때는 “OO님 반갑습니다”, 비 로그인 상태일때는 “로그인”으로 상태에 따라 멘트가 다르다.
해당 페이지에 적절한 로그인 상태가 다르기 때문에 따로 구별을 하였다.
로그인 상태: 홈, 프로젝트, 프로젝트 상세, 프로젝트 등록
비로그인 상태: 로그인, 회원가입
<!-- 로그인 상태 -->
<header>
<div class="header-inner">
<div onClick="location.href='../home.html'" class="logo">
<img src="../images/inq_logo.png" alt="InQ" />
</div>
<div class="menu">
<a href="javascript:void(0)" class="bton login_name">인큐님 반갑습니다</a>
</div>
</div>
</header>
<!-- 비 로그인 상태 -->
<header>
<div class="header-inner">
<div onClick="location.href='../login/index.html'" class="logo">
<img src="../images/inq_logo.png" alt="InQ" />
</div>
<div class="menu">
<a href="javascript:void(0)" class="bton login_name">로그인</a>
</div>
</div>
</header>
footer에 입력할 내용들은 모두 중앙에 위치하게 하였다.
중앙 최상단에는 깃허브 로고를 넣었다. 해당 로고를 누르면 동아리 깃허브 링크로 이동한다.
그리고 임시로 작성한 동아리 이메일과 학교 이름을 작성했다.
최하단에는 copyright 기호와 함께 프로젝트 이름을 작성했다.
<script src="../js/footer.js"></script>
<footer>
<div class="inner">
<div class="info">
<a href="https://github.com/InQ-InQ-InQ-InQ-InQ" class="github-logo">
<img src="../images/github.png" alt="inq_logo" />
</a>
<span>Email : inqiniqinqinqin@gamil.com</span>
<span>Kyounggi Univ.</span>
</div>
<div class="copyright">
© <span class="this-year"></span> InQ Project Manager
</div>
</div>
</footer>
/* Footer */
footer {
background-color: var(--inq-blue);
margin-top: 200px;
color: var(--inq-yellow);
}
footer .inner {
width: 680px;
padding: 80px
}
footer .info .github-logo img {
width: 80px;
margin: 0 auto;
margin-bottom: 20px;
color: var(--inq-yellow);
}
common 파일 연결시키기
html에서 html include 하기
header와 footer는 모든 페이지마다 사용한다. 해당 코드를 매번 추가하는 것은 비효율적이다. 여러 페이지가 존재하기 때문에 유지보수를 하기에 좋지 않기 때문이다.
그래서 header html코드는 header.html에 footer html코드는 footer.html에 따로 입력해두었다. header와 footer의 css는 commom.css에 입력했다.
header와 footer html파일을 각 페이지 파일에 include를 하는 방식을 통해 유지보수성을 높였다.
head 태그에 삽입
<head>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$(document).ready( function() {
$("#headers").load("../common/header.html"); // 원하는 파일 경로를 삽입
});
$(document).ready( function() {
$("#footers").load("../common/footer.html"); // 원하는 파일 경로를 삽입
});
</script>
</head>
- jquery 부르기
- script 태그 사용
- ready 메소드안에 원하는 파일의 경로를 삽입한다.
ready(): js의 DOM 트리가 준비되었을 때 시점을 컨트롤 하는 메소드이다. 해당 메소드는 외부 라이브러리 및 이미지와는 상관없이 DOM 데이터 로드시 바로 사용이 가능하다. (window.onload()보다 더 빨리 실행된다.) 여러번 사용시 선언 순서에 따라 순차적으로 실행된다.
- load()를 사용하여 파일 가져오기
load(): 입력한 데이터를 불러온다.
$(#headers), $(#footers)
body에서 불러올 아이디 이름을 입력한다.
$(선택자).동작함수()
$ 기호는 jquery를 의미하며 jquery에 접근할 수 있는 식별자이다. 선택자를 통해 원하는 html요소를 선택하고 동작함수를 정의하여 선택된 요소에 원하는 동작함수를 설정한다.
$()
: 선택된 HTML 요소를 jquery에서 이용할 수 있는 형태로 생성해준다.
인수로는 HTML 태그, CSS 선택자를 전달하여 특정 HTML 요소를 선택할 수 있다.
$()
함수를 통해 생성된 요소를 jquery 객체(jQuery Object)라고 한다.
body 태그에 삽입
<body>
<div id="headers"></div>
<div id="footers"></div>
</body>
- id를 통해 값 불러오기
head에서 정의했던 id를 불러온다. 해당 id가 가지고 있던 값이 출력된다.
마무리
간단해 보였던 header와 footer였지만 생각보다 고려해야 할 점들이 많았다. 위치라던가, 색상 조합, 기능들 등등…
그리고 header와 footer은 모든 페이지에 공통적으로 들어가는 내용이기 때문에 어떻게 하면 매번 수정할 때마다 코드를 복붙하지 않고 편하게 단 한번으로 변경할 수 있을 까 생각을 했었다.
그때, 3학년 전공수업때 php를 다루며 파일을 include 하던것이 생각났다. php include는 알겠는데 html파일을 html에 include하는 법을 몰라 한참을 서칭해서 겨우 찾아냈다.
하지만 바로 이해가 안되서 코드를 붙혀 넣었지만 안돌아가고… 여러가지 건들여보면서 작동시키게 하는 등 파일 하나 연결하는데 엄청 시간을 사용했던 것 같다. 그래도 이 시간이 언젠가는 피가되고 살이 되겠지..?!
프로젝트 소개
해당 프로젝트는 교내 개발 동아리 InQ에서 진행한 프로젝트이다.
3월 17일에 첫 회의를 시작으로, 4월 30일에 프론트엔드 개발을 시작했다.
프로젝트 이름은 InQ Project Manager 이며, 동아리 활동을 통해 생기는 프로젝트를 관리해 주는 웹 페이지이다.
초보의 프론트엔드 제작
프로젝트 디자인부터 제작까지 모두 혼자 진행했다.
웹 구조, 디자인, 프론트엔드 등.. 우리 팀에서 웹 제작이 가능한 사람이 프론트엔드 한명(나), 백엔드 한명이여서 한달동안 둘이서 제작을 완료할 수 있을 까? 걱정이 많았지만 어찌저지 포기할건 포기하고 살릴건 살리면서 제작을 완료하였다.
일단 나는 미적인 감각은 정말 쥐똥만큼도 없기 때문에… 웹 디자인을 어떻게 할지 정말 걱정과 고민이 많았다. 그런 내가 선택한 최선의 방법은…! 이 프로젝트와 유사한 기존에 존재하던 서비스의 웹 디자인 참고와 내 취향인 웹의 디자인을 참고하여 제작했다.
해당 사이트에 들어가서 검사(F12) 계속 누르면서 html 구조를 어떻게 짰는지 확인하고, 참고하고, 내 방식대로 수정을 계속 거듭하면서 만들었다.

참고한 사이트: 42DoProject, 식스샵
InQ Project Manager 디자인 컨셉
프로젝트 디자인 컨셉은 딱! 뭐다!는 없다. 일단 식스샵의 디자인이 어렵지 않으면서 심플하고 눈에 잘 들어오며 요즘의 웹 디자인이라 생각이 들어서 큰 디자인은 식스샵을 굉장히 많이 참고하면서 만들었다.
확고한 디자인 컨셉은 없지만 시그니처 색은 꼭 있어야 한다고 생각했다. 마침 동아리 로고에 사용한 색들이 눈에 잘 띄면서 색 조합이 잘 어울렸기에 해당 색상을 프로젝트의 시그니처 색으로 사용하였다.
프로젝트 기능
프로젝트의 기능을 크게 4가지로 나누면 다음과 같다.
- 로그인
- 회원가입
- 홈
- 프로젝트
로그인

아이디 및 비밀번호 입력후, 로그인 버튼 클릭시 로그인이 된다. 만약, 회원이 없다면 로그인되지 않는다. (로그인을 하지 않으면 홈으로 넘어가지 않음)
회원가입

로그인 페이지에서 회원가입 버튼 클릭시, 회원가입 페이지로 넘어간다.
회원가입 항목은 9개이다. * 가 붙은 항목들은 required를 통해 필수입력으로 했다.
- 이름 *
- 아이디 *
- 비밀번호 *
- 비밀번호 확인 *
- 이메일 *
- 포지션 *
select를 사용하여 본인의 포지션 1가지를 선택하도로 하였다.
- 보유기술 *
modal창을 제작하여 본인에게 해당하는 보유기술 여러가지를 선택할 수 있도록 했다.
보유기술 버튼 클릭시, modal창이 나오고 checkbox로 되어있는 기술 선택후 완료버튼을 누르면 modal창이 닫히면서 데이터가 넘어간다.
- 깃허브
- 한 줄 소개
가입하기 버튼을 클릭하면 회원가입이 완료된다.
홈
홈 페이지에는 크게 2가지로 나뉘어진다.
프로젝트는 크게 2가지로 나뉘어진다.
- 프로젝트 홈 페이지
모든 프로젝트를 모아둔 홈 페이지이다.
프로젝스 홈 페이지 상단에 검색란이 있다. 찾고 싶은 프로젝트의 진행 상황을 선택한 후, 프로젝트 명을 검색할 수 있다. 진행상황은 모집중,진행중,완료 3가지 이다.
- 프로젝트 등록 페이지
프로젝트 홈 페이지 상단 우측에 프로젝트 등록 버튼이 있다. 해당 버튼을 누르면 새로운 프로젝트를 등록할 수 있다.
프로젝트 등록을 위한 항목은 총 5개이다.
- 프로젝트 이름 *
- 모집완료 기간 *
- 프로젝트 진행 기간(시작~종료) *
- 모집중인 역할 *
버튼을 클릭하면 modal창이 나오며, 여러가지 포지션들을 중복 선택할 수 있다.
- 프로젝트 소개
하단의 프로젝트 등록 버튼을 클릭하면 프로젝트 등록이 완료된다.
- 상세 프로젝트 설명 페이지
프로젝트 홈 페이지에서 보고싶은 프로젝트 카드를 클릭하면 해당 프로젝에 대한 상세 설명 페이지로 넘어간다.
프로젝트 등록 페이지에서 작성한 내용들을 볼 수 있다. 추가로, 현재 모집중인 역할과 참여중인 멤버의 현황을 실시간으로 확인 할 수 있다.
페이지 하단 좌측에 위치한 참여하기 버튼을 클릭하면 해당 프로젝트에 참여가 된다.
추가로, 프로젝트를 등록한 회원에게는 참여하기 버튼 하단에 프로젝트 상태 변경 버튼이 추가로 존재한다. 이 버튼은, 오직 해당 프로젝트를 등록한 회원에게만 보이고 변경이 가능하다. 프로젝트 상태 변경 버튼을 클릭하면 modal창이 나오고 radio형식의 모집중, 진행중, 완료를 선택할 수 있다. 상태 선택 후 완료 버튼을 누르면 해당 프로젝트의 상태가 변경된다.
마무리
프로젝트를 제작하면서 많은 난관을 마주했다. 일단, 나는 프로젝트를 누군가와 같이 해본적이 처음이었으며 각자의 포지션을 나누어서 진행한 것은 더더욱 생소한 경험이었다.
각자 역할을 나누어 진행하고 추후에 프론트와 백엔드를 연동하면서 생각지도 못한 오류들이 너무 많았다. 내가 노트북에서 서버 열어서 보면 멀쩡한데 팀원 노트북에서는 깨진다던가.. 기능이 먹히지 않는다던가.. 정확한 원인을 찾지 못한 것이 아직도 있지만! 해결한 것도 많기 때문에 스트레스와 뿌듯함을 동시에 얻을 수 있는 경험이었다.
다음번에 팀으로 프로젝트를 진행한다면 이러한 점들을 더욱 고려하고 바로바로 적용시켜 보는 등을 통해 개선해 나가야 겠다.
InQ Project Manager에 대한 간단한 소개와 소감을 마치며, 해당 프로젝트의 frontend 부분을 제작하면서 발생했던 오류나, 새롭게 적용해본 기능, 상세한 기능 설명 등은 각 페이지 기능 설명란에 작성하도록 하겠다.