Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
6a03414
Merge pull request #28 from shyjnnn/eva
shyjnnn Apr 1, 2023
2c50dbe
docs: README 요구사항 update - 구현 완료
shyjnnn Apr 9, 2023
d74adb4
refactor: 불필요한 removeEventListner 제거
shyjnnn Apr 9, 2023
6be699e
fix: 최초 접속 시 eye-slash여도 비밀번호 보이는 이슈
shyjnnn Apr 9, 2023
34164d9
Merge pull request #45 from shyjnnn/main
Apr 14, 2023
596d91d
refactor: 들여쓰기 formating
shyjnnn Apr 14, 2023
588bff4
style: 함수 style arrow로 변경
shyjnnn Apr 15, 2023
d0a5220
docs: Week4 요구사항 update
shyjnnn Apr 15, 2023
9937188
style: html title 변경
shyjnnn Apr 15, 2023
16a8419
feat: card compoenet 생성
shyjnnn Apr 15, 2023
54e0e15
docs: card compoenet 목업 데이터 생성
shyjnnn Apr 15, 2023
2ad4989
feat: card-list-compoenet 생성
shyjnnn Apr 15, 2023
dbb2eca
feat: shared html card-list-component 추가
shyjnnn Apr 15, 2023
6d70510
feat: card component css 구현
shyjnnn Apr 15, 2023
0c100b4
feat: gnb component 구현 및 css 적용
shyjnnn Apr 15, 2023
69fa4ba
feat: footer component 구현 및 css 적용
shyjnnn Apr 15, 2023
a209d13
feat: searchBar Component 구현 및 css 적용
shyjnnn Apr 15, 2023
aa302ef
feat: shared 레이아웃 및 css 구현
shyjnnn Apr 15, 2023
865a612
feat: card-list-component grid 적용
shyjnnn Apr 15, 2023
68218a6
refactor: 경로 수정 및 불필요한 주석, console 제거
shyjnnn Apr 15, 2023
4eff8e1
feat: media query 적용
shyjnnn Apr 15, 2023
45dbbcb
feat: global_style_css에 color 변수 등록 및 전체 적용
shyjnnn Apr 16, 2023
1d22b0d
refactor: connectedCallback 등록
shyjnnn Apr 16, 2023
a8a612f
refactor: card connectedCallback 등록
shyjnnn Apr 16, 2023
a51d198
feat: card star component 구현 및 toggle 기능 추가
shyjnnn Apr 16, 2023
ab1d203
feat: 로그인 여부에 따른 gnb 수정
shyjnnn Apr 16, 2023
e2ccbc1
feat: 로그인 시 sessionStorage에 저장
shyjnnn Apr 16, 2023
64708d7
feat: card 컴포넌트 mouse hover 이벤트 구현
shyjnnn Apr 16, 2023
a6429e1
feat: card 컴포넌트 z-index 부여
shyjnnn Apr 16, 2023
9693db0
feat: 자잘한 css 수정
shyjnnn Apr 16, 2023
153accd
fix: global css 경로 절대경로로 수정
shyjnnn Apr 16, 2023
37581f3
feat: icon update
shyjnnn Apr 16, 2023
0e5d32d
feat: px rem으로 변경
shyjnnn Apr 16, 2023
508e26d
fix: card 부모 요소 삐져나가는 이슈
shyjnnn Apr 16, 2023
ccf15ae
refactor: gnb 및 footer 컴포넌트로 변경
shyjnnn Apr 16, 2023
06e4b19
feat: 카드 클릭 시 codeit 홈페이지로 이동 구현
shyjnnn Apr 16, 2023
22147f9
docs: 요구사항 구현 완료 update
shyjnnn Apr 16, 2023
ddd380b
Merge branch 'eva' into eva-week4
shyjnnn Apr 16, 2023
f43e081
feat: star component event 버블링 방지
shyjnnn Apr 16, 2023
72c233c
Merge branch 'eva-week4' of https://github.com/shyjnnn/Weekly-Mission…
shyjnnn Apr 16, 2023
cadb730
refactor: star 컴포넌트 toggle 메소드 attributeChangedCallback으로 변경
shyjnnn Apr 18, 2023
ffb939f
refactor: gnb 컴포넌트 login 리팩토링
shyjnnn Apr 19, 2023
e2d98d5
refactor: footer 컴포넌트 DOM 노드 create 분리
shyjnnn Apr 19, 2023
25ab06b
refactor: seachBar 컴포넌트 DOM 노드 create 분리
shyjnnn Apr 19, 2023
7ddfa22
refactor: cardlist와 fetch card data 분리
shyjnnn Apr 19, 2023
6787233
refactor: cardlist url 은닉화
shyjnnn Apr 19, 2023
503def0
refactor: gnb 컴포넌트 isLoggedIn 은닉화
shyjnnn Apr 19, 2023
9efcf53
refactor: star 컴포넌트 isStarred 은닉화 및 event handler 분리
shyjnnn Apr 19, 2023
6eaec08
feat: folderInfo 컴포넌트 생성
shyjnnn Apr 19, 2023
d0c1dfe
feat: folder api 생성
shyjnnn Apr 19, 2023
d5786d2
feat: folderInfo 컴포넌트로 folder api로 받아온 데이터 전송
shyjnnn Apr 19, 2023
ba19353
fix: folderInfo 컴포넌트의 stylesheet 적용 안되는 이슈 수정
shyjnnn Apr 19, 2023
b4f7734
rename: js파일명 camelCase로 변경
shyjnnn Apr 19, 2023
56552b6
Merge pull request #53 from shyjnnn/eva-week4
Apr 19, 2023
87f333c
feat: gnb 컴포넌트에 user api로 받아온 데이터 전송
shyjnnn Apr 19, 2023
1198e0e
docs: update README.md
shyjnnn Apr 19, 2023
47c4ae7
chore: 불필요한 콘솔문 제거
shyjnnn Apr 19, 2023
1aef5ea
feat: card component에 folder api에서 받아온 데이터 전송
shyjnnn Apr 19, 2023
4c988ea
feat: 카드 생성날짜 포맷에 맞게 변경
shyjnnn Apr 19, 2023
2096e2a
chore: 불필요한 함수 및 import문 제거
shyjnnn Apr 20, 2023
14bd4d9
feat: cardComponent로 데이터 전달하는 방식 변경
shyjnnn Apr 20, 2023
bd72146
feat: cardCreate에 현재 날짜와 카드 생성날짜 차이 계산 후 포맷팅 적용
shyjnnn Apr 20, 2023
4dd01ef
docs: README 구현완료 사항 update
shyjnnn Apr 20, 2023
bfeac81
refactor: gnb Component DOM 구성 template으로 변경
shyjnnn Apr 20, 2023
b42aad5
chore(mentor): star Component 프로퍼티명 변경 및 style 노드 생성 template으로 변경
shyjnnn Apr 20, 2023
89939b6
refactor(mentor): 구조 변경 및 hover css로 변경
shyjnnn Apr 22, 2023
4609f0b
fix: global css 미적용 버그 해결
shyjnnn Apr 22, 2023
7158c81
chore(mentor): 코드리뷰 반영
shyjnnn Apr 22, 2023
bcabc1d
fix: footerComponent { 버그 해결
shyjnnn Apr 22, 2023
c103fbc
Merge pull request #60 from shyjnnn/eva-week5
Aningaaq Apr 26, 2023
9623225
docs: delete readme.md
shyjnnn Jun 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 1 addition & 45 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,3 @@
# Weekly-Mission

## Week 3

### 필수 요구사항

#### 전체

- [x] 로고 클릭시 루트 페이지(“/”)로 이동해야 합니다.
- [x] 로그인 페이지, 회원가입 페이지 모두 로고위 상단 여백이 동일해야 합니다.
- [x] input 요소에 focus in 일 때, input 안에 문자열은 검정색이어야 하고, 파랑색 테두리가 생겨야 합니다.
- [x] input 요소에 focus out 일 때, input 안에 문자열과 테두리는 회색이어야 합니다.
- [x] SNS 아이콘들은 클릭 가능함을 확인할 수 있고, 클릭시 각각 “https://www.google.com/”, “https://www.kakaocorp.com/page/” 으로 이동합니다.

#### 로그인페이지

- [x] 회원 가입하기는 클릭 가능함을 확인할 수 있고, 클릭시 “/signup” 페이지로 이동합니다.
- [x] 이메일 input에서 focus out 일 때, 값이 없을 경우 alert으로 “이메일을 입력해주세요.” 메세지를 보입니다.
- [x] 이메일 input에서 focus out 일 때, 값이 있고, 이메일 형식에 맞지 않을 경우 alert으로 “올바른 이메일 주소가 아닙니다.” 메세지를 보입니다.
- [x] 이메일: [email protected], 비밀번호: codeit101 으로 로그인 시도할 경우, “/my-link” 페이지로 이동합니다.
- [x] 이외의 로그인 시도의 경우, “이메일과 비밀번호를 확인해주세요.” 메세지가 담긴 alert 을 띄워 주세요.
- [x] 로그인 버튼 클릭 또는 Enter키 입력으로 로그인 실행돼야 합니다.
- [x] 비밀번호 찾기는 클릭 가능함을 확인할 수 있고, 클릭시 “/forgot-password” 페이지로 이동합니다.

#### 회원가입 페이지

- [x] 로그인 하기는 클릭 가능함을 확인할 수 있고, 클릭시 “/signin” 페이지로 이동합니다.
- [x] 이메일 input에서 focus out 일 때, 값이 없을 경우 alert으로 “이메일을 입력해주세요.” 메세지를 보입니다.
- [x] 이메일 input에서 focus out 일 때, 값이 있고, 이메일 형식에 맞지 않을 경우 alert으로 “올바른 이메일 주소가 아닙니다.” 메세지를 보입니다.
- [x] 이메일 input에서 focus out 일 때, input 값이 [email protected] 일 경우, alert으로 “이미 사용 중인 아이디입니다.” 메세지를 보입니다.
- [x] 비밀번호 input에서 focus out 일 때, 값이 없거나 문자열만 있거나 숫자만 있는 경우, alert으로 “비밀번호는 영문, 숫자 조합 8자 이상 입력해 주세요.” 메세지를 보입니다.
- [x] 회원가입을 실행할 경우, 문제가 있는 경우 문제가 있는 부분을 alert 메세지로 알립니다.
- [x] 이외의 유효한 회원가입 시도의 경우, “/my-link”로 이동합니다.
- [x] 회원가입 버튼 클릭 또는 Enter키 입력으로 회원가입 실행돼야 합니다.

#### 모바일 크기

- [x] 375px 보다 작은 크기의 기기는 고려하지 않습니다.
- [x] 좌우 여백 32px 제외하고 내부 요소들이 너비를 모두 차지합니다.
- [x] 내부 요소들의 너비는 기기의 너비가 커질수록 커지지만 400px을 넘지 않습니다.

### 선택 요구사항

#### 전체

- [x] 비밀번호 input 요소에 비밀번호를 확인할 수 있는 아이콘을 추가합니다.
- [x] 비밀번호를 확인할 수 있는 아이콘 클릭시 비밀번호의 문자열이 보이기도 하고, 가려지기도 합니다.
## Week 4
1 change: 1 addition & 0 deletions api/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BASE_URL = "https://bootcamp-api.codeit.kr";
8 changes: 8 additions & 0 deletions api/folder.api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { BASE_URL } from "./common.js";

const folderUrl = BASE_URL + "/api/sample/folder";
export async function fetchFolderData() {
const response = await fetch(folderUrl);
const { data } = await response.json();
return data;
}
9 changes: 9 additions & 0 deletions api/user.api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BASE_URL } from "./common.js";

const userUrl = BASE_URL + "/api/sample/user";

export async function fetchUserData() {
const response = await fetch(userUrl);
const { data } = await response.json();
return data;
}
99 changes: 99 additions & 0 deletions components/card/card-component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
@import url("/static/css/global_style.css");

.card-container {
position: relative;
display: flex;
flex-direction: column;
filter: drop-shadow(0rem 0.5rem 2.5rem rgba(0, 0, 0, 0.08));
border-radius: 2.5rem;
overflow: hidden;
width: 34rem;
height: 33.4rem;
background-color: var(--linkbrary-white);
}

.card-container:hover .card-image {
transform: scale(1.2);
}

.card-container:hover .card-info {
background-color: var(--library-white-smoke);
}

.card-image {
height: 20rem;
object-fit: cover;
overflow: hidden;
display: block;
}

.star-icon {
position: absolute;
top: 1.6rem;
right: 1.6rem;
z-index: 1;
}

.card-info {
padding: 1.5rem 2rem;
position: relative;
z-index: 1;
height: 13.4rem;
}

.card-info-head {
display: flex;
width: 100%;
justify-content: space-between;
}

.card-update-time {
font-weight: 400;
font-size: 1.3rem;
line-height: 1.6rem;
color: #666666;
}

.kebab-icon {
width: 2.1rem;
height: 1.7rem;
}

.card-description {
font-weight: 500;
font-size: 1.6rem;
line-height: 2.4rem;
margin: 1rem auto;

text-overflow: ellipsis;
overflow: hidden;
word-break: break-word;

display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}

.card-date {
font-weight: 400;
font-size: 1.5rem;
line-height: 1.8rem;

color: #333333;
}

@media screen and (max-width: 767px) {
.card-container {
width: 32.5rem;
height: 32.7rem;
}

.card-image {
width: 32.5rem;
}

.card-info {
height: 13.5rem;
padding: 1.5rem 2rem;
}
}
25 changes: 25 additions & 0 deletions components/card/card-list-component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@import url("/static/css/global_style.css");

.card-list-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
justify-items: center;
gap: 2rem;

margin-bottom: 10rem;
}

@media screen and (max-width: 1100px) {
.card-list-container {
grid-template-columns: repeat(2, 1fr);
}
}

@media screen and (max-width: 767px) {
.card-list-container {
grid-template-columns: repeat(1, 1fr);
gap: 2.5rem;
margin-top: 1.2rem;
margin-bottom: 6rem;
}
}
114 changes: 114 additions & 0 deletions components/card/cardComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { StarComponent } from "../star/starComponent.js";
export class CardComponent extends HTMLElement {
#prop = null;
constructor() {
super();

this.shadow = this.attachShadow({ mode: "open" });
}

connectedCallback() {
this.render();
}

get prop() {
return this.#prop;
}

set prop(newProp) {
// 타입체킹 로직 추후 추가
if (typeof newProp !== "object" && newProp !== null) {
console.warn("올바르지 않은 형식의 데이터가 들어왔습니다.");
return;
}
if (
typeof newProp.imageSrc !== "string" ||
typeof newProp.description !== "string" ||
typeof newProp.date !== "string" ||
typeof newProp.url !== "string"
) {
console.warn("올바르지 않은 형식의 데이터가 들어왔습니다.");
return;
}
this.#prop = newProp;
}

calculateTimeDiff(dateString) {
const updatedDate = new Date(dateString);
const today = new Date();
const timeDiff = today - updatedDate;

const MINUTE = 60 * 1000;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const MONTH = DAY * 31;
const YEAR = DAY * 365;

const timeUnits = [
{ value: YEAR, label: "year" },
{ value: MONTH, label: "month" },
{ value: DAY, label: "day" },
{ value: HOUR, label: "hour" },
{ value: MINUTE, label: "minute" },
];

for (let i = 0; i < timeUnits.length; i++) {
const { value, label } = timeUnits[i];

if (timeDiff < value) {
continue;
}

const formattedTimeDiff = Math.floor(timeDiff / value);

return (
formattedTimeDiff +
" " +
label +
(formattedTimeDiff > 1 ? "s" : "") +
" ago"
);
}
}

parseDate(dateString) {
const date = new Date(dateString);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return [year, month, day].join(". ");
}

get template() {
return `
<div class="card-container">
<img class="card-image" src="${this.prop.imageSrc}" />
<span class="star-icon"></span>
<div class="card-info">
<div class="card-info-head">
<div class="card-update-time">${this.calculateTimeDiff(
this.prop.date
)}</div>
<img class="kebab-icon" src="/static/imgs/kebab.svg" />
</div>
<div class="card-description">${this.prop.description}</div>
<div class="card-date">${this.parseDate(this.prop.date)}</div>
</div>
</div>
`;
}
render() {
// CSS
const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "stylesheet");
linkElem.setAttribute("href", "/components/card/card-component.css");
this.shadow.appendChild(linkElem);
const cardComponent = document.createElement("template");
cardComponent.innerHTML = this.template;
this.shadow.appendChild(cardComponent.content.cloneNode(true));

const starIcon = new StarComponent();
this.shadow.querySelector(".star-icon").appendChild(starIcon);
}
}
customElements.define("card-component", CardComponent);
56 changes: 56 additions & 0 deletions components/card/cardListComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { CardComponent } from "./cardComponent.js";

class CardListComponent extends HTMLElement {
#prop = null;

constructor() {
super();
this.attachShadow({ mode: "open" });
}

connectedCallback() {
this.render();
}

get prop() {
return this.#prop;
}

set prop(newProp) {
// type checking 추후 구현
this.#prop = newProp;
this.renderCards();
}

createCard() {
const cardComponent = new CardComponent();
return cardComponent;
}

renderCards() {
this.prop.forEach((card) => {
const cardComponent = this.createCard();
cardComponent.prop = {
imageSrc: card.imageSource ?? "/static/imgs/default-card-img.png",
description: card.description,
date: card.createdAt,
url: card.url,
};
this.cardListContainer.appendChild(cardComponent);
});
}

render() {
const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "stylesheet");
linkElem.setAttribute("href", "/components/card/card-list-component.css");
this.shadowRoot.appendChild(linkElem);

const cardListContainer = document.createElement("div");
cardListContainer.classList.add("card-list-container");
this.shadowRoot.appendChild(cardListContainer);
this.cardListContainer = cardListContainer;
}
}

customElements.define("card-list-component", CardListComponent);
Loading