diff --git a/css/account.css b/auth/account.css similarity index 94% rename from css/account.css rename to auth/account.css index 70eaed89..027d4382 100644 --- a/css/account.css +++ b/auth/account.css @@ -91,8 +91,8 @@ body { color: #3692ff; } -/* 로그인/회원가입 버튼 */ -.form button { +/* 로그인/회원가입 버튼 auth-button */ +.auth-button { width: 100%; height: 56px; background-color: #9ca3af; @@ -101,14 +101,10 @@ body { font-weight: 600; border: none; border-radius: 25px; - cursor: pointer; + /* cursor: pointer; */ margin-top: 10px; } -.form button:hover { - background-color: #3578e5; -} - /* 간편 로그인 배치 */ .easy-login { display: flex; @@ -166,9 +162,13 @@ body { font-size: 1.4rem; } +.input-error { + border: 1.5px solid #f74747 !important; +} + /* 태블릿과 PC에서는 동일한 스타일을 유지하므로 별도 스타일 변경 없음 */ /* 아이패드 에어를 기준으로 구현하였습니다. (820 x 1180) */ -@media (min-width: 768px) and (max-width: 1199px) { +@media (max-width: 1199px) { } /* 모바일 반응형 구현 */ @@ -198,7 +198,7 @@ body { width: 100%; } - .form button { + .auth-button { width: 100%; } diff --git a/auth/login-validation.js b/auth/login-validation.js new file mode 100644 index 00000000..e21ce83d --- /dev/null +++ b/auth/login-validation.js @@ -0,0 +1,68 @@ +import { emailInput, passwordInput, emailPattern, emailError, passwordError, loginBtn, isEmailValid, isPasswordValid } from "./validation-common.js"; + +// 이메일 유효성 검사 함수 +const emailCheck = () => { + // 이메일 값 공백 제거 후 가져오기. + const emailValue = emailInput.value.trim(); + isEmailValid.value = false; + + if (emailValue === "") { + emailError.textContent = "이메일을 입력해주세요."; + emailError.style.display = "block"; + emailInput.classList.add("input-error"); + } else if (!emailPattern.test(emailValue)) { + emailError.textContent = "잘못된 이메일 형식입니다."; + emailError.style.display = "block"; + emailInput.classList.add("input-error"); + } else { + emailError.style.display = "none"; + emailInput.classList.remove("input-error"); + isEmailValid.value = true; + } + + loginBtnToggle(); +}; + +// 패스워드 유효성 검사 함수 +const passwordCheck = () => { + const passwordValue = passwordInput.value.trim(); + isPasswordValid.value = false; + + if (passwordValue === "") { + passwordError.textContent = "비밀번호를 입력해주세요."; + passwordError.style.display = "block"; + passwordInput.classList.add("input-error"); + } else if (passwordValue.length < 8) { + passwordError.textContent = "비밀번호를 8자 이상 입력해주세요."; + passwordError.style.display = "block"; + passwordInput.classList.add("input-error"); + } else { + passwordError.style.display = "none"; + passwordInput.classList.remove("input-error"); + isPasswordValid.value = true; + } + + loginBtnToggle(); +}; + +// 이메일, 패스워드 유효성 검사에 따른 로그인 버튼 활성화 함수 +const loginBtnToggle = () => { + if (isEmailValid.value && isPasswordValid.value) { + loginBtn.style.backgroundColor = "#3578e5"; + loginBtn.style.cursor = "pointer"; + loginBtn.disabled = false; + } else { + loginBtn.style.backgroundColor = "#9ca3af"; + loginBtn.style.color = "#f3f4f6"; + loginBtn.style.cursor = "not-allowed"; + loginBtn.disabled = true; + } +}; + +// focusout 이벤트 +emailInput.addEventListener("focusout", emailCheck); +passwordInput.addEventListener("focusout", passwordCheck); + +// 초기 로그인 버튼 비활성화 +loginBtn.disabled = true; +loginBtn.style.cursor = "not-allowed"; diff --git a/auth/signup-validation.js b/auth/signup-validation.js new file mode 100644 index 00000000..9d9a48e7 --- /dev/null +++ b/auth/signup-validation.js @@ -0,0 +1,100 @@ +import { + emailInput, + nameInput, + passwordInput, + passwordCheckInput, + emailPattern, + emailError, + passwordError, + passwordCheckError, + signupBtn, + isEmailValid, + isPasswordValid, + isPasswordCheckValid, +} from "./validation-common.js"; + +// 이메일 유효성 검사 함수 +const emailCheck = () => { + // 이메일 값 공백 제거 후 가져오기. + const emailValue = emailInput.value.trim(); + isEmailValid.value = false; + + if (emailValue === "") { + emailError.textContent = "이메일을 입력해주세요."; + emailError.style.display = "block"; + emailInput.classList.add("input-error"); + } else if (!emailPattern.test(emailValue)) { + emailError.textContent = "잘못된 이메일 형식입니다."; + emailError.style.display = "block"; + emailInput.classList.add("input-error"); + } else { + emailError.style.display = "none"; + emailInput.classList.remove("input-error"); + isEmailValid.value = true; + } + + signupBtnToggle(); +}; + +// 패스워드 유효성 검사 함수 +const passwordCheck = () => { + const passwordValue = passwordInput.value.trim(); + isPasswordValid.value = false; + + if (passwordValue === "") { + passwordError.textContent = "비밀번호를 입력해주세요."; + passwordError.style.display = "block"; + passwordInput.classList.add("input-error"); + } else if (passwordValue.length < 8) { + passwordError.textContent = "비밀번호를 8자 이상 입력해주세요."; + passwordError.style.display = "block"; + passwordInput.classList.add("input-error"); + } else { + passwordError.style.display = "none"; + passwordInput.classList.remove("input-error"); + isPasswordValid.value = true; + } + + passwordDblCheck(); // 비밀번호 확인 후, 비밀번호 수정 시 이를 감지 하지 못해서 추가. (즉시 검사하는 함수) + signupBtnToggle(); +}; + +const passwordDblCheck = () => { + const passwordCheckValue = passwordCheckInput.value.trim(); + const passwordValue = passwordInput.value.trim(); + isPasswordCheckValid.value = false; + + if (passwordCheckValue !== passwordValue) { + passwordCheckError.textContent = "비밀번호가 일치하지 않습니다."; + passwordCheckInput.classList.add("input-error"); + passwordCheckError.style.display = "block"; + } else { + passwordCheckError.style.display = "none"; + passwordCheckInput.classList.remove("input-error"); + isPasswordCheckValid.value = true; + } + + signupBtnToggle(); +}; + +const signupBtnToggle = () => { + if (isEmailValid.value && isPasswordValid.value && isPasswordCheckValid.value) { + signupBtn.style.backgroundColor = "#3578e5"; + signupBtn.style.cursor = "pointer"; + signupBtn.disabled = false; + } else { + signupBtn.style.backgroundColor = "#9ca3af"; + signupBtn.style.color = "#f3f4f6"; + signupBtn.style.cursor = "not-allowed"; + signupBtn.disabled = true; + } +}; + +// focusout 이벤트 +emailInput.addEventListener("focusout", emailCheck); +passwordInput.addEventListener("focusout", passwordCheck); +passwordCheckInput.addEventListener("focusout", passwordDblCheck); + +// 회원가입 버튼 요소 초기 상태 설정 +signupBtn.style.cursor = "not-allowed"; +signupBtn.disabled = true; diff --git a/js/login_password_showing.js b/auth/toggle-password.js similarity index 99% rename from js/login_password_showing.js rename to auth/toggle-password.js index 77e79448..34d2c3be 100644 --- a/js/login_password_showing.js +++ b/auth/toggle-password.js @@ -3,6 +3,7 @@ * @param {input태그 id} inputId * @param {i 태그 자신} iconElement */ + const togglePasswordVisibility = (inputId, iconElement) => { const passwordInput = document.getElementById(inputId); const isPassword = passwordInput.type === "password"; diff --git a/auth/validation-common.js b/auth/validation-common.js new file mode 100644 index 00000000..89d978c2 --- /dev/null +++ b/auth/validation-common.js @@ -0,0 +1,25 @@ +// 공통 입력 요소 ( 이메일, 비밀번호) +export const emailInput = document.querySelector("#form-email"); +export const passwordInput = document.querySelector("#form-password"); + +// 회원가입 전용 입력 요소 (닉네임, 비밀번호 확인) +export const nameInput = document.querySelector("#form-name"); +export const passwordCheckInput = document.querySelector("#form-password-check"); + +// 에러 메시지 요소 (이메일, 패스워드, 패스워드 확인) +export const emailError = document.querySelector("#email-error"); +export const passwordError = document.querySelector("#password-error"); +export const passwordCheckError = document.querySelector("#password-check-error"); + +// 로그인 및 회원가입 버튼 +export const loginBtn = document.querySelector("#btn-login"); +export const signupBtn = document.querySelector("#btn-signup"); + +// 유효성 검사 패턴 +export const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; + +// 유효성 검사 상태 변수 +// 원시타입으로 내보내면 에러가 났음.. 객체로 관리 +export let isEmailValid = { value: false }; +export let isPasswordValid = { value: false }; +export let isPasswordCheckValid = { value: false }; diff --git a/css/common.css b/common/common.css similarity index 95% rename from css/common.css rename to common/common.css index 4e50c824..08f6b439 100644 --- a/css/common.css +++ b/common/common.css @@ -20,6 +20,7 @@ --white: #ffffff; --background: #cfe5ff; --skyblue: #e6f2ff; + --error-red: #f74747; } html { diff --git a/html/login.html b/html/login.html deleted file mode 100644 index 729c5820..00000000 --- a/html/login.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - Login - - -
-
- 판다마켓 이미지 - - -
-
- - diff --git a/images/Preview-Image.jpg b/images/thumbnail.jpg similarity index 100% rename from images/Preview-Image.jpg rename to images/thumbnail.jpg diff --git a/index.html b/index.html index 42e017d4..7b371ee3 100644 --- a/index.html +++ b/index.html @@ -4,18 +4,18 @@ - + - + - + @@ -27,11 +27,11 @@ /> - - + + - + 판다마켓 - 로그인 + 로그인
@@ -62,7 +62,7 @@

거래해보세요

- 구경하러 가기 + 구경하러 가기
일상의 모든 물건을 거래해보세요 @@ -116,7 +116,7 @@

- 믿을 수 있는
+ 믿을 수 있는
판다마켓 중고거래

@@ -130,8 +130,8 @@

©codeit - 2024 diff --git a/html/faq.html b/pages/faq.html similarity index 100% rename from html/faq.html rename to pages/faq.html diff --git a/css/style.css b/pages/index.css similarity index 100% rename from css/style.css rename to pages/index.css diff --git a/html/items.html b/pages/items.html similarity index 100% rename from html/items.html rename to pages/items.html diff --git a/pages/login.html b/pages/login.html new file mode 100644 index 00000000..b2b7593e --- /dev/null +++ b/pages/login.html @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Login + + + + + diff --git a/html/privacy.html b/pages/privacy.html similarity index 100% rename from html/privacy.html rename to pages/privacy.html diff --git a/html/signup.html b/pages/signup.html similarity index 51% rename from html/signup.html rename to pages/signup.html index f5f1703a..79ea2462 100644 --- a/html/signup.html +++ b/pages/signup.html @@ -5,12 +5,26 @@ + + + + + + + + + + + + + - - + + - - + + + + + +
+ + +

- + - - - - -
-

- 이미 회원이신가요? - 로그인 -

-
+ + + + + +
+

+ 이미 회원이신가요? + 로그인 +

+
diff --git a/js/mobile_changeImg.js b/ui/mobile-header-image.js similarity index 99% rename from js/mobile_changeImg.js rename to ui/mobile-header-image.js index 20439a00..6471c8d2 100644 --- a/js/mobile_changeImg.js +++ b/ui/mobile-header-image.js @@ -1,7 +1,6 @@ /** * 모바일일 때, headerImg의 src를 변경하는 함수 */ - const mobileChangeImg = () => { // 헤더 판다마켓 로고 태그 const headerImg = document.querySelector(".headerImg");