Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 8 additions & 5 deletions login/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<link rel="icon" href="../images/favi.ico">
<link rel="stylesheet" href="../reset.css">
<link rel="stylesheet" href="./login.css" />
<script src="./login-main.js" type="module"></script>
</head>
<body>
<main>
Expand All @@ -16,14 +17,16 @@
<img src="../images/logo-title.png" alt="판다마켓 로고" />
</a>
</div>
<form class="login__form" method="POST">
<form class="login__form" method="get" action="../items/">
<fieldset>
<label for="user-email">이메일</label>
<input type="text" id="user-email" name="user-email" placeholder="이메일을 입력해주세요"/>
<label for="user-password">비밀번호</label>
<input id="user-password" type="password" name="user-password" placeholder="비밀번호를 입력해주세요"/>
<input id="toggle-visibility-pw" type="checkbox"/>
<label aria-label="비밀번호 표시 여부" aria-checked="false" for="toggle-visibility-pw"></label>
<div class="container__position-relative">
<label for="user-password">비밀번호</label>
<input id="user-password" type="password" name="user-password" placeholder="비밀번호를 입력해주세요"/>
<input id="toggle-visibility-pw" type="checkbox"/>
<label aria-label="비밀번호 표시 여부" aria-checked="false" for="toggle-visibility-pw"></label>
</div>
<button type="submit">로그인</button>
</fieldset>
<div class="login__alert">
Expand Down
7 changes: 7 additions & 0 deletions login/login-main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createValidRule, ruleObj, emailInput, passwordInput } from '../modules/validation-rule.mjs';
import { initValidation } from '../modules/validate.mjs';
import { initPasswordVisibility, visibilityPw } from '../modules/toggle-visibility-pw.mjs';

const loginValidationState = createValidRule({ emailInput, passwordInput }, ruleObj); //네이밍구조 페이지 기반으로 바꾸기
initValidation(loginValidationState);
initPasswordVisibility({ visibilityPw });
41 changes: 33 additions & 8 deletions login/login.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
@import url(../global.css);

.container__position-relative {
position: relative;
}

main {
padding: 0 16px;
}
Expand Down Expand Up @@ -28,12 +32,11 @@ fieldset {
flex-direction: column;
width: 100%;
border: none;
position: relative;
}

label[for="toggle-visibility-pw"] {
position: absolute;
top: 152px;
top: 52px;
right: 24px;
display: inline-block;
width: 24px;
Expand Down Expand Up @@ -67,22 +70,19 @@ input {
background-color: var(--secondary-gray100);
height: 56px;
padding: 12px 24px;
width: 100%;
}

button {
height: 56px;
padding: 16px 124px;
border-radius: 40px;
background-color: var(--primary-color);
background-color: var(--secondary-gray400);
color: var(--white-color);
margin-bottom: 24px;
font-size: 20px;
}

button:hover {
background-color: var(--primary-hover);
}

.login__alert {
height: 74px;
background-color: #e6f2ff;
Expand Down Expand Up @@ -119,6 +119,31 @@ button:hover {
color: var(--primary-color);
}

/* validation err 관련 스타일 */
.error-message {
/* err메세지 */
color: red;
font-size: 14px;
line-height: 26px;
padding-left: 24px;
display: block;
margin-top: -16px;
margin-bottom: 16px;
}

.error-Line {
/* 인풋 빨간 라인*/
border: 1px solid red;
}

.pass-button {
background-color: var(--primary-color);
}

.pass-button:hover {
background-color: var(--primary-hover);
}

@media screen and (min-width: 768px) {
.main__login {
max-width: 640px;
Expand All @@ -131,7 +156,7 @@ button:hover {
}

label[for="toggle-visibility-pw"] {
top: 180px;
top: 60px;
}

form label {
Expand Down
23 changes: 23 additions & 0 deletions modules/toggle-visibility-pw.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 비밀번호 보기 토글버튼들(chekBox)
export const visibilityPw = document.querySelector("#toggle-visibility-pw");
export const visibilityPwCheck = document.querySelector("#toggle-visibility-pwcheck");

function togglePasswordVisibility(targetInput, targetLabel) {
const isPassword = targetInput.type === "password";
targetInput.type = isPassword ? "text" : "password";
targetLabel.setAttribute('aria-checked', isPassword ? 'true' : 'false');
}

export function initPasswordVisibility(toggleBtns) {
Object.values(toggleBtns).forEach((toggleBtn) => {
if (!toggleBtn) return;

const targetInput = toggleBtn.previousElementSibling;
const targetLabel = toggleBtn.nextElementSibling;
if (!targetInput || targetInput.type !== "password") return;

toggleBtn.addEventListener("click", () => {
togglePasswordVisibility(targetInput, targetLabel);
});
});
}
54 changes: 54 additions & 0 deletions modules/validate.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { removeMessage, appendErr, clearErr, updateButton } from './validation-ui.mjs';

const userForm = document.querySelector("form");

// 검사 통과 못한 거 있나요?
export function hasInvalidInput(validationState) {
return Object.values(validationState).some(validator => validator.passed === false);
}

//폼 전송 막기
function preventInvalidSubmit(e, validationState) {
//서브밋 누르면 통과 못한 인풋에 경고 보여줘
Object.values(validationState).forEach((validator) => {
updateValidation({ currentTarget: validator.input }, validationState);
});

if (hasInvalidInput(validationState)) {
e.preventDefault();
}
}

//스타일 추가할지 말지 판단
function updateValidation(e, validationState) {
const { name } = e.currentTarget;
const validator = validationState[name];

removeMessage(name)

if (!validator.condition()) {
appendErr(validator);
validator.passed = false;
} else {
clearErr(validator);
validator.passed = true;
}

updateButton(validationState, hasInvalidInput);
}

//리스너 추가
export function initValidation(validationState) {
for (let validator in validationState) {
validationState[validator].input.addEventListener("focusout", e => updateValidation(e, validationState));
}

userForm.addEventListener("submit", e => preventInvalidSubmit(e, validationState));

if (validationState['user-password-check']) {
validationState['user-password'].input.addEventListener("focusout", () => {
// 비밀번호 변경되었을 때 비밀번호 확인도 같이
updateValidation({ currentTarget: validationState['user-password-check'].input }, validationState);
});
}
}
60 changes: 60 additions & 0 deletions modules/validation-rule.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
export const emailInput = document.querySelector("#user-email");
export const passwordInput = document.querySelector("#user-password");
export const nameInput = document.querySelector("#user-name");
export const passwordCheckInput = document.querySelector("#user-password-check");

// 전체 검사 조건
export const ruleObj = {
'user-email': {
input: emailInput,
isValid() {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.input.value);
},
getErrorMessage() {
return this.input.value ? "잘못된 이메일입니다." : "이메일을 입력해주세요"
},
},
'user-password': {
input: passwordInput,
isValid() {
return this.input.value.length >= 8;
},
getErrorMessage() {
return (this.input.value.length == 0) ? "비밀번호를 입력해주세요." : "비밀번호를 8자 이상 입력해주세요."
},
},
'user-name': {
input: nameInput,
isValid() {
return this.input.value;
},
getErrorMessage() {
return "닉네임을 입력해주세요";
},
},
'user-password-check': {
input: passwordCheckInput,
isValid() {
return (passwordInput.value === this.input.value) && passwordCheckInput.value.length != 0;
},
getErrorMessage() {
return "비밀번호가 일치하지 않습니다."
},
}
}

// 해당 페이지에 있는 인풋만 규칙 만들기
export function createValidRule(inputElement, ruleObj) {
const validRule = {}

Object.values(inputElement).forEach((input) => {
validRule[input.name] = {
input,
condition: ruleObj[input.name].isValid,
createMsg: ruleObj[input.name].getErrorMessage,
passed: false,
}
});

return validRule;
}
26 changes: 26 additions & 0 deletions modules/validation-ui.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const submitBtn = document.querySelector("button");

//존재하는 실패 메세지 삭제
export function removeMessage(name) {
const msg = document.querySelector(`#${name}+.error-message`);
if (msg) msg.remove();
}

// 검사 실패 메세지 추가
export function appendErr(validator) {
validator.input.classList.add("error-Line");
const err = document.createElement("span");
err.classList.add("error-message");
err.textContent = validator.createMsg();
validator.input.insertAdjacentElement("afterend", err);
}

// 검사 실패 스타일 삭제
export function clearErr(validator) {
validator.input.classList.remove("error-Line");
}

// 버튼 스타일 추가
export function updateButton(validationState, hasInvalidInput) {
submitBtn.classList.toggle("pass-button", !hasInvalidInput(validationState));
}
23 changes: 14 additions & 9 deletions sign_up/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<link rel="icon" href="../images/favi.ico">
<link rel="stylesheet" href="../reset.css">
<link rel="stylesheet" href="./sign-up.css" />
<script src="./sign-up-main.js" type="module"></script>
</head>
<body>
<main>
Expand All @@ -16,20 +17,24 @@
<img src="../images/logo-title.png" alt="판다마켓 로고" />
</a>
</div>
<form class="sign-up__form" method="POST">
<form class="sign-up__form" method="get" action="../login/">
<fieldset>
<label for="user-email">이메일</label>
<input type="text" id="user-email" name="user-email" placeholder="이메일을 입력해주세요"/>
<label for="user-name">닉네임</label>
<input id="user-name" type="text" name="user-name" placeholder="닉네임을 입력해주세요"/>
<label for="user-password">비밀번호</label>
<input id="user-password" type="password" name="user-password" placeholder="비밀번호를 입력해주세요"/>
<label for="user-password">비밀번호 확인</label>
<input id="user-password-check" type="password" name="user-password-check" placeholder="비밀번호를 다시 한 번 입력해주세요"/>
<input id="toggle-visibility-pw" type="checkbox"/>
<label aria-label="비밀번호 표시 여부" aria-checked="false" for="toggle-visibility-pw"></label>
<input id="toggle-visibility-pwcheck" type="checkbox"/>
<label aria-label="비밀번호 확인 표시 여부" aria-checked="false" for="toggle-visibility-pwcheck"></label>
<div class="container__position-relative">
<label for="user-password">비밀번호</label>
<input id="user-password" type="password" name="user-password" placeholder="비밀번호를 입력해주세요"/>
<input id="toggle-visibility-pw" type="checkbox"/>
<label aria-label="비밀번호 표시 여부" aria-checked="false" for="toggle-visibility-pw"></label>
</div>
<div class="container__position-relative">
<label for="user-password">비밀번호 확인</label>
<input id="user-password-check" type="password" name="user-password-check" placeholder="비밀번호를 다시 한 번 입력해주세요"/>
<input id="toggle-visibility-pwcheck" type="checkbox"/>
<label aria-label="비밀번호 확인 표시 여부" aria-checked="false" for="toggle-visibility-pwcheck"></label>
</div>
<button type="submit">회원가입</button>
</fieldset>
<div class="sign-up__alert">
Expand Down
7 changes: 7 additions & 0 deletions sign_up/sign-up-main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createValidRule, ruleObj, emailInput, passwordInput, nameInput, passwordCheckInput } from '../modules/validation-rule.mjs';
import { initValidation } from '../modules/validate.mjs';
import { initPasswordVisibility, visibilityPw, visibilityPwCheck } from '../modules/toggle-visibility-pw.mjs';

const singUpValidationState = createValidRule({ emailInput, passwordInput, nameInput, passwordCheckInput }, ruleObj);
initValidation(singUpValidationState);
initPasswordVisibility({ visibilityPw, visibilityPwCheck });
14 changes: 4 additions & 10 deletions sign_up/sign-up.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,9 @@ label[for="toggle-visibility-pwcheck"] {
cursor: pointer;
}

label[for="toggle-visibility-pw"] {
top: 258px;
}

label[for="toggle-visibility-pw"],
label[for="toggle-visibility-pwcheck"] {
top: 360px;
top: 46px;
}

#toggle-visibility-pwcheck {
Expand Down Expand Up @@ -90,12 +87,9 @@ label[for="toggle-visibility-pwcheck"] {
width: 396px;
}

label[for="toggle-visibility-pw"] {
top: 304px;
}

label[for="toggle-visibility-pw"],
label[for="toggle-visibility-pwcheck"] {
top: 424px;
top: 58px;
}
}

Expand Down
Loading