diff --git a/mission2/.DS_Store b/mission2/.DS_Store index 32d3fd95..bd8a44de 100644 Binary files a/mission2/.DS_Store and b/mission2/.DS_Store differ diff --git a/mission2/common.css b/mission2/common.css deleted file mode 100644 index 3e0c7677..00000000 --- a/mission2/common.css +++ /dev/null @@ -1,195 +0,0 @@ -/* Common styles for all pages */ - -/* Default styles (Mobile: 375px ~ 767px) */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -a { - text-decoration: none; -} - -h1 { - font-size: 32px; -} - -button { - background: none; - border: none; - outline: none; - box-shadow: none; - cursor: pointer; -} - -header { - width: 100%; - height: 60px; - background-color: #ffffff; - position: sticky; - top: 0; - left: 0; /* 화면 전체를 덮도록 좌측 고정 */ - right: 0; /* 화면 전체를 덮도록 우측 고정 */ - z-index: 10; -} - -.header-container { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0 16px; /* 모바일 여백 16px */ - max-width: 375px; /* 모바일 최대 너비 */ - margin: 0 auto; /* 가운데 정렬 */ - height: 100%; /* 헤더 높이 전체 사용 */ -} - -footer { - background-color: #111827; - color: #9ca3af; - display: flex; - flex-direction: column; - gap: 20px; - padding: 24px 16px 60px; - font-size: 14px; -} - -#footerMenu { - display: flex; - justify-content: center; - gap: 20px; - color: #e5e7eb; -} - -#footerMenu > a { - color: #e5e7eb; -} - -#socialMedia { - display: flex; - justify-content: center; - gap: 12px; -} - -/* Common button styles */ -.button { - background-color: #3692ff; - color: #ffffff; - display: inline-flex; - align-items: center; - justify-content: center; -} - -.button:hover { - background-color: #1967d6; -} - -.button:focus { - background-color: #1251aa; -} - -.button:disabled { - background-color: #9ca3af; - cursor: default; - pointer-events: none; -} - -#loginButton { - font-size: 14px; - font-weight: 600; - border-radius: 8px; - padding: 8px 16px; -} - -#pill-button { - font-size: 16px; - font-weight: 700; - border-radius: 999px; - padding: 12px 80px; -} - -/* Tablet: 768px ~ 1199px */ -@media screen and (min-width: 768px) and (max-width: 1199px) { - h1 { - font-size: 36px; - } - - header { - height: 65px; - } - - .header-container { - padding: 0 24px; /* 태블릿 여백 24px */ - max-width: 960px; /* 태블릿 최대 너비 */ - margin: 0 auto; - } - - footer { - flex-direction: row; - justify-content: space-between; - padding: 28px 40px 80px; - font-size: 15px; - } - - #footerMenu { - gap: 25px; - } - - #socialMedia { - justify-content: flex-end; - } - - #loginButton { - font-size: 15px; - padding: 10px 20px; - } - - #pill-button { - font-size: 18px; - padding: 14px 100px; - } -} - -/* PC: 1200px 이상 */ -@media screen and (min-width: 1200px) { - h1 { - font-size: 40px; - } - - header { - height: 70px; - } - - .header-container { - padding: 0; /* PC에서는 패딩 제거 */ - max-width: 1200px; /* PC 최대 너비 */ - margin: 0 auto; - display: flex; - justify-content: space-between; /* 양 끝으로 벌어짐 */ - } - - footer { - flex-direction: row; - justify-content: space-between; - padding: 32px 200px 108px; - font-size: 16px; - } - - #footerMenu { - gap: 30px; - } - - #socialMedia { - justify-content: flex-end; - } - - #loginButton { - font-size: 16px; - padding: 11.5px 23px; - } - - #pill-button { - font-size: 20px; - padding: 16px 124px; - } -} diff --git a/mission2/faq.html b/mission2/faq.html index d38d621e..3367409c 100644 --- a/mission2/faq.html +++ b/mission2/faq.html @@ -6,6 +6,6 @@ Document - 임시 FAQ 페이지 + 향후 작성 예정 diff --git a/mission2/images/.DS_Store b/mission2/images/.DS_Store deleted file mode 100644 index dc967bb1..00000000 Binary files a/mission2/images/.DS_Store and /dev/null differ diff --git a/mission2/images/Img_home_01.png b/mission2/images/Img_home_01.png deleted file mode 100644 index a22916b7..00000000 Binary files a/mission2/images/Img_home_01.png and /dev/null differ diff --git a/mission2/images/Img_home_02.png b/mission2/images/Img_home_02.png deleted file mode 100644 index 7e1af94a..00000000 Binary files a/mission2/images/Img_home_02.png and /dev/null differ diff --git a/mission2/images/Img_home_03.png b/mission2/images/Img_home_03.png deleted file mode 100644 index 90dcbd06..00000000 Binary files a/mission2/images/Img_home_03.png and /dev/null differ diff --git a/mission2/images/Img_home_bottom.png b/mission2/images/Img_home_bottom.png deleted file mode 100644 index 07e8e9c0..00000000 Binary files a/mission2/images/Img_home_bottom.png and /dev/null differ diff --git a/mission2/images/Img_home_top.png b/mission2/images/Img_home_top.png deleted file mode 100644 index c79c2f92..00000000 Binary files a/mission2/images/Img_home_top.png and /dev/null differ diff --git a/mission2/images/favicon.ico b/mission2/images/favicon.ico deleted file mode 100644 index 9699dbc0..00000000 Binary files a/mission2/images/favicon.ico and /dev/null differ diff --git a/mission2/images/home/bottom-banner-image.png b/mission2/images/home/bottom-banner-image.png new file mode 100644 index 00000000..4a5f85b2 Binary files /dev/null and b/mission2/images/home/bottom-banner-image.png differ diff --git a/mission2/images/home/feature1-image.png b/mission2/images/home/feature1-image.png new file mode 100644 index 00000000..4684b9a7 Binary files /dev/null and b/mission2/images/home/feature1-image.png differ diff --git a/mission2/images/home/feature2-image.png b/mission2/images/home/feature2-image.png new file mode 100644 index 00000000..31e20b97 Binary files /dev/null and b/mission2/images/home/feature2-image.png differ diff --git a/mission2/images/home/feature3-image.png b/mission2/images/home/feature3-image.png new file mode 100644 index 00000000..5b8084a7 Binary files /dev/null and b/mission2/images/home/feature3-image.png differ diff --git a/mission2/images/home/hero-image.png b/mission2/images/home/hero-image.png new file mode 100644 index 00000000..d28fb652 Binary files /dev/null and b/mission2/images/home/hero-image.png differ diff --git a/mission2/images/ic_facebook.png b/mission2/images/ic_facebook.png deleted file mode 100644 index 58333d45..00000000 Binary files a/mission2/images/ic_facebook.png and /dev/null differ diff --git a/mission2/images/ic_instagram.png b/mission2/images/ic_instagram.png deleted file mode 100644 index 98e24ea6..00000000 Binary files a/mission2/images/ic_instagram.png and /dev/null differ diff --git a/mission2/images/ic_twitter.png b/mission2/images/ic_twitter.png deleted file mode 100644 index 5df0852d..00000000 Binary files a/mission2/images/ic_twitter.png and /dev/null differ diff --git a/mission2/images/ic_youtube.png b/mission2/images/ic_youtube.png deleted file mode 100644 index f51731d4..00000000 Binary files a/mission2/images/ic_youtube.png and /dev/null differ diff --git a/mission2/images/icons/eye-invisible.svg b/mission2/images/icons/eye-invisible.svg new file mode 100644 index 00000000..92252b05 --- /dev/null +++ b/mission2/images/icons/eye-invisible.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/mission2/images/icons/eye-visible.svg b/mission2/images/icons/eye-visible.svg new file mode 100644 index 00000000..35a75305 --- /dev/null +++ b/mission2/images/icons/eye-visible.svg @@ -0,0 +1,3 @@ + + + diff --git a/mission2/images/login_page/.DS_Store b/mission2/images/login_page/.DS_Store deleted file mode 100644 index 90735bda..00000000 Binary files a/mission2/images/login_page/.DS_Store and /dev/null differ diff --git a/mission2/images/login_page/btn_visibility_on_24px.png b/mission2/images/login_page/btn_visibility_on_24px.png deleted file mode 100644 index 2a13ff43..00000000 Binary files a/mission2/images/login_page/btn_visibility_on_24px.png and /dev/null differ diff --git a/mission2/images/login_page/googleLogo.png b/mission2/images/login_page/googleLogo.png deleted file mode 100644 index 49852a6b..00000000 Binary files a/mission2/images/login_page/googleLogo.png and /dev/null differ diff --git a/mission2/images/login_page/kakaoLogo.png b/mission2/images/login_page/kakaoLogo.png deleted file mode 100644 index 01ef8b47..00000000 Binary files a/mission2/images/login_page/kakaoLogo.png and /dev/null differ diff --git a/mission2/images/login_page/pandaMarketLogo.png b/mission2/images/login_page/pandaMarketLogo.png deleted file mode 100644 index 7db8527a..00000000 Binary files a/mission2/images/login_page/pandaMarketLogo.png and /dev/null differ diff --git a/mission2/images/logo/favicon.ico b/mission2/images/logo/favicon.ico new file mode 100644 index 00000000..9fecc692 Binary files /dev/null and b/mission2/images/logo/favicon.ico differ diff --git a/mission2/images/logo/logo.svg b/mission2/images/logo/logo.svg new file mode 100644 index 00000000..d497acbf --- /dev/null +++ b/mission2/images/logo/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/mission2/images/logo/og-image.png b/mission2/images/logo/og-image.png new file mode 100644 index 00000000..e7d7b5bf Binary files /dev/null and b/mission2/images/logo/og-image.png differ diff --git a/mission2/images/panda home.png b/mission2/images/panda home.png deleted file mode 100644 index 878496fc..00000000 Binary files a/mission2/images/panda home.png and /dev/null differ diff --git a/mission2/images/signup_page/.DS_Store b/mission2/images/signup_page/.DS_Store deleted file mode 100644 index cfc10bc7..00000000 Binary files a/mission2/images/signup_page/.DS_Store and /dev/null differ diff --git a/mission2/images/signup_page/btn_visibility_on_24px.png b/mission2/images/signup_page/btn_visibility_on_24px.png deleted file mode 100644 index 2a13ff43..00000000 Binary files a/mission2/images/signup_page/btn_visibility_on_24px.png and /dev/null differ diff --git a/mission2/images/signup_page/googleLogo.png b/mission2/images/signup_page/googleLogo.png deleted file mode 100644 index 49852a6b..00000000 Binary files a/mission2/images/signup_page/googleLogo.png and /dev/null differ diff --git a/mission2/images/signup_page/kakaoLogo.png b/mission2/images/signup_page/kakaoLogo.png deleted file mode 100644 index 01ef8b47..00000000 Binary files a/mission2/images/signup_page/kakaoLogo.png and /dev/null differ diff --git a/mission2/images/signup_page/pandaMarketLogo.png b/mission2/images/signup_page/pandaMarketLogo.png deleted file mode 100644 index 7db8527a..00000000 Binary files a/mission2/images/signup_page/pandaMarketLogo.png and /dev/null differ diff --git a/mission2/images/social/facebook-logo.svg b/mission2/images/social/facebook-logo.svg new file mode 100644 index 00000000..8491c2f8 --- /dev/null +++ b/mission2/images/social/facebook-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/mission2/images/social/google-logo.png b/mission2/images/social/google-logo.png new file mode 100644 index 00000000..199f3d62 Binary files /dev/null and b/mission2/images/social/google-logo.png differ diff --git a/mission2/images/social/instagram-logo.svg b/mission2/images/social/instagram-logo.svg new file mode 100644 index 00000000..c83306f8 --- /dev/null +++ b/mission2/images/social/instagram-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/mission2/images/social/kakao-logo.png b/mission2/images/social/kakao-logo.png new file mode 100644 index 00000000..bfadc1d3 Binary files /dev/null and b/mission2/images/social/kakao-logo.png differ diff --git a/mission2/images/social/twitter-logo.svg b/mission2/images/social/twitter-logo.svg new file mode 100644 index 00000000..14a6069a --- /dev/null +++ b/mission2/images/social/twitter-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/mission2/images/social/youtube-logo.svg b/mission2/images/social/youtube-logo.svg new file mode 100644 index 00000000..5fcc0ff3 --- /dev/null +++ b/mission2/images/social/youtube-logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/mission2/index.css b/mission2/index.css deleted file mode 100644 index 02c4ed53..00000000 --- a/mission2/index.css +++ /dev/null @@ -1,265 +0,0 @@ -/* Default styles (Mobile: 375px ~ 767px) */ -.wrap { - max-width: 100%; - margin: 0 auto; - padding: 0 16px; -} - -.section_sub1, -.section_sub3 { - width: 100%; - height: 400px; - background-color: #cfe5ff; -} - -.section_sub1 { - position: relative; - background-image: url("images/Img_home_top.png"); - display: flex; - align-items: center; - background-repeat: no-repeat; - background-position: 80% bottom; - background-size: 65%; -} - -.sub1_descrip, -.sub3_descrip { - position: absolute; - left: 50%; - top: 25%; - transform: translate(-50%, -50%); - align-items: center; - text-align: center; -} - -.sub1_descrip h1, -.sub3_descrip h1, -.sub1_descrip .button, -.sub3_descrip .button { - white-space: nowrap; -} - -.section_sub3 { - position: relative; - background-image: url("images/Img_home_bottom.png"); - display: flex; - align-items: center; - background-repeat: no-repeat; - background-position: center bottom; /* 모바일에서 가운데 정렬 */ - background-size: 65%; -} - -.section_sub2, -.section_sub3, -.section_sub4 { - width: 100%; - height: 500px; -} - -.descrip { - padding: 80px 0; - display: flex; - flex-direction: column; - align-items: center; - gap: 24px; -} - -/* 검색 섹션 특별 스타일 */ -.section_sub2 .descrip { - text-align: left; -} - -.section_sub2:first-of-type .descrip { - text-align: right; -} - -@media screen and (max-width: 1199px) { - .section_sub2:first-of-type .descrip { - flex-direction: column-reverse; - } -} - -.descrip:nth-child(odd) { - text-align: left; -} - -.descrip:nth-child(even) { - text-align: right; -} - -.item-tag { - color: #3692ff; - font-size: 16px; - line-height: 22px; - font-weight: 700; - margin-bottom: 10px; -} - -.item-description { - font-size: 20px; - font-weight: 500; - line-height: 120%; - letter-spacing: 0.08em; - margin-top: 20px; -} - -/* 검색 섹션 스타일 수정: 모든 해상도에서 우측 정렬 */ -.search-section { - text-align: right; /* 기본적으로 우측 정렬 */ -} - -.search-section .item-summary { - text-align: right; /* 텍스트 우측 정렬 */ -} - -/* Tablet: 768px ~ 1199px */ -@media screen and (min-width: 768px) and (max-width: 1199px) { - .wrap { - max-width: 960px; - padding: 0 40px; - } - - .section_sub1, - .section_sub3 { - height: 480px; - } - - .section_sub2, - .section_sub3, - .section_sub4 { - height: 600px; - } - - .descrip { - padding: 100px 0; - flex-direction: column; - gap: 32px; - } - - .item-tag { - font-size: 17px; - line-height: 24px; - margin-bottom: 11px; - } - - .item-description { - font-size: 22px; - margin-top: 22px; - } - - .sub1_descrip, - .sub3_descrip { - top: 20%; - width: 100%; - } - - .sub1_descrip h1, - .sub3_descrip h1 { - white-space: normal; /* 태블릿에서
무시하고 한 줄로 표시 */ - } - - /* 검색 섹션 스타일 수정: 태블릿에서 우측 정렬 유지 */ - .search-section { - text-align: right; - flex-direction: column-reverse; /* 기존 스타일 유지 */ - } - - .search-section .item-summary { - text-align: right; - } - - /* .section_sub3 이미지 가운데 정렬 */ - .section_sub3 { - background-position: center bottom; /* 태블릿에서 가운데 정렬 */ - } -} - -/* PC: 1200px 이상 */ -@media screen and (min-width: 1200px) { - .wrap { - max-width: 1200px; - padding: 0; - } - - .section_sub1, - .section_sub3 { - height: 540px; - background-size: 55%; - } - - .sub1_descrip { - left: 200px; - bottom: 20%; - top: auto; - transform: none; - text-align: left; - width: auto; - } - - .sub3_descrip { - left: 200px; - bottom: 30%; - top: auto; - transform: none; - text-align: left; - width: auto; - } - - .sub1_descrip h1, - .sub3_descrip h1 { - white-space: normal; - } - - .section_sub2, - .section_sub3, - .section_sub4 { - height: 720px; - } - - .descrip { - padding: 138px 0; - flex-direction: row; - align-items: center; - gap: 5%; - } - - .descrip:nth-child(odd) { - text-align: left; - } - - .descrip:nth-child(even) { - text-align: right; - } - - .item-tag { - font-size: 18px; - line-height: 25px; - margin-bottom: 12px; - } - - .item-description { - font-size: 24px; - margin-top: 24px; - } - - /* 검색 섹션 스타일 수정: PC에서 우측 정렬 유지 */ - .search-section { - text-align: right; - } - - .search-section .item-summary { - text-align: right; - } - - /* .section_sub3 이미지 우측 정렬 유지 */ - .section_sub3 { - background-position: 80% bottom; /* PC에서는 기존 우측 정렬 유지 */ - } -} - -/* 검색 섹션 특별 스타일 */ -@media screen and (max-width: 1199px) { - .search-section { - flex-direction: column-reverse; - } -} diff --git a/mission2/index.html b/mission2/index.html index 4054095d..4b1f2248 100644 --- a/mission2/index.html +++ b/mission2/index.html @@ -3,84 +3,95 @@ + + + + + + 판다마켓 - + - - + + +
-
- - 판다마켓 홈 - - 로그인 -
+ 판다마켓 홈 + 로그인
-
-
+ -
-
- 인기상품 -
-

Hot item

-

인기 상품을
확인해 보세요

-

+

+
+ 인기 상품 +
+

Hot item

+

+ 인기 상품을
확인해 + 보세요 +

+

가장 HOT한 중고거래 물품을
판다마켓에서 확인해 보세요

-
-
-
-
-

Search

-

구매를 원하는
상품을 검색하세요

-

- 구매하고 싶은 물품은 검색해서
쉽게 찾아보세요 +

+ 검색 기능 +
+

Search

+

+ 구매를 원하는
상품을 + 검색하세요 +

+

+ 구매하고 싶은 물품은 검색해서 +
쉽게 찾아보세요

- 검색
-
-
-
- 상품등록 -
-

Register

-

판매를 원하는
상품을 등록하세요

-

- 어떤 물건이든 판매하고 싶은 상품을
쉽게 등록하세요 +

+ 판매 상품 등록 +
+

Register

+

+ 판매를 원하는
상품을 + 등록하세요 +

+

+ 어떤 물건이든 판매하고 싶은 상품을 +
쉽게 등록하세요

-
-
+
diff --git a/mission2/items.html b/mission2/items.html index a42c143b..3367409c 100644 --- a/mission2/items.html +++ b/mission2/items.html @@ -6,6 +6,6 @@ Document - 임시 아이템 페이지 + 향후 작성 예정 diff --git a/mission2/js/signin.js b/mission2/js/signin.js new file mode 100644 index 00000000..7113d3ea --- /dev/null +++ b/mission2/js/signin.js @@ -0,0 +1,129 @@ +const emailInput = document.getElementById("email"); +const passwordInput = document.getElementById("password"); +const emailError = document.querySelector(".email-error"); +const passwordError = document.querySelector(".password-error"); +const loginButton = document.querySelector('button[type="submit"]'); +const loginForm = document.querySelector("form"); +const togglePasswordButton = document.querySelector( + ".input-wrapper .toggle-password" +); + +// 이메일 유효성 검사 함수 +const validateEmail = () => { + const email = emailInput.value.trim(); + const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; + let isValid = true; + + if (email === "") { + emailError.textContent = "이메일을 입력해주세요."; + emailInput.classList.add("input-error"); + isValid = false; + } else if (!emailRegex.test(email)) { + emailError.textContent = "잘못된 이메일 형식입니다"; + emailInput.classList.add("input-error"); + isValid = false; + } else { + emailError.textContent = ""; + emailInput.classList.remove("input-error"); + } + updateLoginButtonState(); + return isValid; +}; + +// 비밀번호 유효성 검사 함수 +const validatePassword = () => { + const password = passwordInput.value.trim(); + let isValid = true; + + if (password === "") { + passwordError.textContent = "비밀번호를 입력해주세요."; + passwordInput.classList.add("input-error"); // 비밀번호 필드에도 에러 클래스 추가 + isValid = false; + } else if (password.length < 8) { + passwordError.textContent = "비밀번호를 8자 이상 입력해주세요."; + passwordInput.classList.add("input-error"); + isValid = false; + } else { + passwordError.textContent = ""; + passwordInput.classList.remove("input-error"); + } + updateLoginButtonState(); + return isValid; +}; + +// 로그인 버튼 활성화/비활성화 업데이트 함수 +const updateLoginButtonState = () => { + const isEmailValid = + !emailInput.classList.contains("input-error") && + emailInput.value.trim() !== ""; + const isPasswordValid = + !passwordInput.classList.contains("input-error") && + passwordInput.value.trim() !== "" && + passwordInput.value.trim().length >= 8; + + if (isEmailValid && isPasswordValid) { + loginButton.disabled = false; + } else { + loginButton.disabled = true; + } +}; + +// 이벤트 리스너 등록 +emailInput.addEventListener("blur", validateEmail); +passwordInput.addEventListener("blur", validatePassword); + +// 입력 중에도 버튼 상태 업데이트 (선택적, 더 나은 사용자 경험을 위해) +emailInput.addEventListener("input", () => { + // 에러 메시지는 blur 시에만 명확히 표시되도록 input에서는 초기화 가능 + if (emailInput.classList.contains("input-error")) { + emailError.textContent = ""; + emailInput.classList.remove("input-error"); + } + updateLoginButtonState(); +}); +passwordInput.addEventListener("input", () => { + if (passwordInput.classList.contains("input-error")) { + passwordError.textContent = ""; + passwordInput.classList.remove("input-error"); + } + updateLoginButtonState(); +}); + +// 폼 제출 이벤트 처리 +loginForm.addEventListener("submit", (event) => { + event.preventDefault(); // 기본 폼 제출 방지 + + // 최종 유효성 검사 + const isEmailValidOnSubmit = validateEmail(); + const isPasswordValidOnSubmit = validatePassword(); + + if (isEmailValidOnSubmit && isPasswordValidOnSubmit) { + // 유효할 경우 /items.html 로 이동 + window.location.href = "items.html"; // '/items' 대신 'items.html' 사용 + } else { + // 유효하지 않으면 버튼 비활성화 (이미 updateLoginButtonState에서 처리됨) + console.log("Login failed: Invalid input"); + } +}); + +// 페이지 로드 시 초기 버튼 상태 설정 +updateLoginButtonState(); + +// 비밀번호 보이기/숨기기 토글 함수 +if (togglePasswordButton && passwordInput) { + togglePasswordButton.addEventListener("click", () => { + // 비밀번호 필드의 type을 변경 (password <-> text) + const type = + passwordInput.getAttribute("type") === "password" ? "text" : "password"; + passwordInput.setAttribute("type", type); + + // 아이콘 이미지 변경 + if (type === "password") { + togglePasswordButton.src = "images/icons/eye-invisible.svg"; + togglePasswordButton.alt = "비밀번호 숨김"; + } else { + togglePasswordButton.src = "images/icons/eye-visible.svg"; + togglePasswordButton.alt = "비밀번호 보임"; + } + }); +} diff --git a/mission2/js/signup.js b/mission2/js/signup.js new file mode 100644 index 00000000..2afa24c3 --- /dev/null +++ b/mission2/js/signup.js @@ -0,0 +1,246 @@ +const emailInput = document.getElementById("email"); +const nicknameInput = document.getElementById("nickname"); +const passwordInput = document.getElementById("password"); +const passwordConfirmationInput = document.getElementById( + "passwordConfirmation" +); + +const emailError = document.querySelector(".email-error"); +const nicknameError = document.querySelector(".nickname-error"); +const passwordError = document.querySelector(".password-error"); +const passwordConfirmationError = document.querySelector( + ".password-confirmation-error" +); + +const signupButton = document.querySelector('button[type="submit"]'); +const signupForm = document.querySelector("form"); +const togglePasswordButtons = document.querySelectorAll( + ".input-wrapper .toggle-password" +); + +// 이메일 유효성 검사 함수 (signin.js와 동일) +const validateEmail = () => { + const email = emailInput.value.trim(); + const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; + let isValid = true; + + if (email === "") { + emailError.textContent = "이메일을 입력해주세요."; + emailInput.classList.add("input-error"); + isValid = false; + } else if (!emailRegex.test(email)) { + emailError.textContent = "잘못된 이메일 형식입니다"; + emailInput.classList.add("input-error"); + isValid = false; + } else { + emailError.textContent = ""; + emailInput.classList.remove("input-error"); + } + updateSignupButtonState(); + return isValid; +}; + +// 닉네임 유효성 검사 함수 +const validateNickname = () => { + const nickname = nicknameInput.value.trim(); + let isValid = true; + + if (nickname === "") { + nicknameError.textContent = "닉네임을 입력해주세요."; + nicknameInput.classList.add("input-error"); + isValid = false; + } else { + nicknameError.textContent = ""; + nicknameInput.classList.remove("input-error"); + } + updateSignupButtonState(); + return isValid; +}; + +// 비밀번호 유효성 검사 함수 +const validatePassword = () => { + const password = passwordInput.value.trim(); + let isValid = true; + + if (password === "") { + passwordError.textContent = "비밀번호를 입력해주세요."; + passwordInput.classList.add("input-error"); + isValid = false; + } else if (password.length < 8) { + passwordError.textContent = "비밀번호를 8자 이상 입력해주세요."; + passwordInput.classList.add("input-error"); + isValid = false; + } else { + passwordError.textContent = ""; + passwordInput.classList.remove("input-error"); + } + // 비밀번호 확인 필드도 함께 검증 + validatePasswordConfirmation(); + updateSignupButtonState(); + return isValid; +}; + +// 비밀번호 확인 유효성 검사 함수 +const validatePasswordConfirmation = () => { + const password = passwordInput.value.trim(); + const passwordConfirmation = passwordConfirmationInput.value.trim(); + let isValid = true; + + // 먼저 비밀번호 확인 자체의 빈 값 체크 + if (passwordConfirmation === "") { + passwordConfirmationError.textContent = + "비밀번호를 다시 한 번 입력해 주세요."; // 요구사항에는 없었지만 추가 + passwordConfirmationInput.classList.add("input-error"); + isValid = false; + } else if (password !== passwordConfirmation) { + passwordConfirmationError.textContent = "비밀번호가 일치하지 않습니다."; + passwordConfirmationInput.classList.add("input-error"); + isValid = false; + } else { + passwordConfirmationError.textContent = ""; + passwordConfirmationInput.classList.remove("input-error"); + } + updateSignupButtonState(); + return isValid; +}; + +// 회원가입 버튼 활성화/비활성화 업데이트 함수 +const updateSignupButtonState = () => { + const isEmailValid = + !emailInput.classList.contains("input-error") && + emailInput.value.trim() !== ""; + const isNicknameValid = + !nicknameInput.classList.contains("input-error") && + nicknameInput.value.trim() !== ""; + const isPasswordValid = + !passwordInput.classList.contains("input-error") && + passwordInput.value.trim() !== "" && + passwordInput.value.trim().length >= 8; + const isPasswordConfirmationValid = + !passwordConfirmationInput.classList.contains("input-error") && + passwordConfirmationInput.value.trim() !== "" && + passwordInput.value.trim() === passwordConfirmationInput.value.trim(); + + if ( + isEmailValid && + isNicknameValid && + isPasswordValid && + isPasswordConfirmationValid + ) { + signupButton.disabled = false; + } else { + signupButton.disabled = true; + } +}; + +// 이벤트 리스너 등록 +emailInput.addEventListener("blur", validateEmail); +nicknameInput.addEventListener("blur", validateNickname); +passwordInput.addEventListener("blur", validatePassword); +passwordConfirmationInput.addEventListener( + "blur", + validatePasswordConfirmation +); + +// 입력 중에도 버튼 상태 업데이트 +emailInput.addEventListener("input", () => { + if (emailInput.classList.contains("input-error")) { + emailError.textContent = ""; + emailInput.classList.remove("input-error"); + } + updateSignupButtonState(); +}); +nicknameInput.addEventListener("input", () => { + if (nicknameInput.classList.contains("input-error")) { + nicknameError.textContent = ""; + nicknameInput.classList.remove("input-error"); + } + updateSignupButtonState(); +}); +passwordInput.addEventListener("input", () => { + if (passwordInput.classList.contains("input-error")) { + passwordError.textContent = ""; + passwordInput.classList.remove("input-error"); + } + // 비밀번호 입력 시 확인 필드 에러도 업데이트 + if ( + passwordConfirmationInput.value.trim() !== "" && + passwordInput.value.trim() === passwordConfirmationInput.value.trim() + ) { + if (passwordConfirmationInput.classList.contains("input-error")) { + passwordConfirmationError.textContent = ""; + passwordConfirmationInput.classList.remove("input-error"); + } + } + updateSignupButtonState(); +}); +passwordConfirmationInput.addEventListener("input", () => { + if (passwordConfirmationInput.classList.contains("input-error")) { + passwordConfirmationError.textContent = ""; + passwordConfirmationInput.classList.remove("input-error"); + } + // 확인 입력 시, 원본 비밀번호 유효성에 영향은 없지만, 일치 여부는 확인해야 함 + if ( + passwordInput.value.trim() !== "" && + passwordInput.value.trim() === passwordConfirmationInput.value.trim() + ) { + // 일치하면 에러 제거 (위 blur 로직과 유사하게) + passwordConfirmationError.textContent = ""; + passwordConfirmationInput.classList.remove("input-error"); + } + updateSignupButtonState(); +}); + +// 폼 제출 이벤트 처리 +signupForm.addEventListener("submit", (event) => { + event.preventDefault(); // 기본 폼 제출 방지 + + // 최종 유효성 검사 + const isEmailValidOnSubmit = validateEmail(); + const isNicknameValidOnSubmit = validateNickname(); + const isPasswordValidOnSubmit = validatePassword(); + const isPasswordConfirmationValidOnSubmit = validatePasswordConfirmation(); + + if ( + isEmailValidOnSubmit && + isNicknameValidOnSubmit && + isPasswordValidOnSubmit && + isPasswordConfirmationValidOnSubmit + ) { + // 유효할 경우 signin.html 로 이동 + window.location.href = "signin.html"; + } else { + console.log("Signup failed: Invalid input"); + } +}); + +// 페이지 로드 시 초기 버튼 상태 설정 +updateSignupButtonState(); + +// 비밀번호 보이기/숨기기 토글 함수 ( signup.html 용) +const setupPasswordToggle = (passwordField, toggleButton) => { + if (toggleButton && passwordField) { + toggleButton.addEventListener("click", () => { + const type = + passwordField.getAttribute("type") === "password" ? "text" : "password"; + passwordField.setAttribute("type", type); + + if (type === "password") { + toggleButton.src = "images/icons/eye-invisible.svg"; + toggleButton.alt = "비밀번호 숨김"; + } else { + toggleButton.src = "images/icons/eye-visible.svg"; + toggleButton.alt = "비밀번호 보임"; + } + }); + } +}; + +// 각 비밀번호 필드에 토글 기능 설정 +if (togglePasswordButtons.length > 0) { + setupPasswordToggle(passwordInput, togglePasswordButtons[0]); // 첫 번째 아이콘은 passwordInput 용 + if (togglePasswordButtons.length > 1) { + // 두 번째 아이콘이 있는 경우 (비밀번호 확인 필드용) + setupPasswordToggle(passwordConfirmationInput, togglePasswordButtons[1]); + } +} diff --git a/mission2/login.css b/mission2/login.css deleted file mode 100644 index 52221fd7..00000000 --- a/mission2/login.css +++ /dev/null @@ -1,260 +0,0 @@ -/* Default styles (Mobile: 375px ~ 767px) */ -main { - max-width: 100%; - margin: 0 auto; - padding: 0 16px; /* 좌우 여백 16px 유지 */ -} - -.login_homebutton_logo { - display: block; - text-align: center; - margin-top: 40px; - margin-bottom: 32px; - width: 100%; /* 전체 너비 차지 */ - max-width: 400px; /* 최대 너비 400px 제한 */ - margin-left: auto; - margin-right: auto; -} - -.login_homebutton_logo img { - width: 280px; - height: auto; -} - -.input_item { - margin-bottom: 24px; - width: 100%; /* 전체 너비 차지 */ - max-width: 400px; /* 최대 너비 400px 제한 */ - margin-left: auto; - margin-right: auto; -} - -.input_item label { - display: block; - margin-bottom: 16px; - font-size: 16px; - font-weight: 700; -} - -.input_item input { - padding: 14px 20px; - background-color: #f3f4f6; - border: none; - border-radius: 12px; - font-size: 14px; - line-height: 20px; - width: 100%; /* input도 부모 너비를 따름 */ - box-sizing: border-box; /* 패딩 포함 너비 계산 */ -} - -.input_with_icon { - position: relative; - width: 100%; /* 부모(.input_item)와 동일한 너비 */ -} - -.input_with_icon input { - padding: 14px 50px 14px 20px; /* 오른쪽 패딩을 아이콘 공간으로 설정 */ - width: 100%; /* 부모(.input_with_icon)와 동일한 너비 */ - box-sizing: border-box; /* 패딩 포함 너비 계산 */ -} - -.pill-button { - display: block; /* 블록 요소로 설정 */ - font-size: 18px; - font-weight: 700; - border-radius: 999px; - padding: 14px 0; - width: 100%; /* 전체 너비 차지 */ - max-width: 400px; /* 최대 너비 400px 제한 */ - margin: 0 auto; /* 가운데 정렬 */ -} - -.social_login { - display: block; /* 블록 요소로 설정 */ - background-color: #e6f2ff; - border-radius: 8px; - padding: 14px 20px; /* .input_item input과 동일한 패딩 */ - margin: 16px 0; /* 마진 줄임 (기존 20px -> 16px) */ - width: 100%; /* 전체 너비 차지 */ - max-width: 400px; /* 최대 너비 400px 제한 */ - margin-left: auto; - margin-right: auto; - display: flex; - align-items: center; - justify-content: space-between; - box-sizing: border-box; /* 패딩 포함 너비 계산 */ -} - -.btn_visibility { - position: absolute; - right: 16px; - top: 50%; - transform: translateY(-50%); -} - -.swith_to_otherpage { - display: block; - text-align: center; - font-size: 14px; - width: 100%; /* 전체 너비 차지 */ - max-width: 400px; /* 최대 너비 400px 제한 */ - margin-left: auto; - margin-right: auto; -} - -a { - text-decoration: underline; - color: #3182f6; -} - -/* Tablet: 768px ~ 1199px */ -@media screen and (min-width: 768px) and (max-width: 1199px) { - main { - max-width: 640px; - padding: 0 24px; - } - - .login_homebutton_logo { - margin-top: 50px; - margin-bottom: 36px; - } - - .login_homebutton_logo img { - width: 340px; - } - - .input_item { - margin-bottom: 24px; - width: 100%; /* 전체 너비 차지 */ - max-width: 592px; /* 태블릿 최대 너비 (640px - 24px * 2) */ - margin-left: auto; - margin-right: auto; - } - - .input_item label { - font-size: 17px; - } - - .input_item input { - padding: 15px 22px; - font-size: 15px; - line-height: 22px; - width: 100%; - } - - .input_with_icon { - width: 100%; - } - - .input_with_icon input { - padding: 15px 50px 15px 22px; /* 오른쪽 패딩을 아이콘 공간으로 설정 */ - width: 100%; - } - - .pill-button { - display: block; - font-size: 19px; - padding: 15px 0; - width: 100%; - max-width: 592px; /* 태블릿 최대 너비 */ - margin: 0 auto; - } - - .social_login { - display: block; - padding: 15px 22px; /* .input_item input과 동일한 패딩 */ - margin: 18px 0; /* 마진 줄임 (기존 22px -> 18px) */ - width: 100%; - max-width: 592px; /* 태블릿 최대 너비 */ - margin-left: auto; - margin-right: auto; - display: flex; - align-items: center; - justify-content: space-between; - box-sizing: border-box; - } - - .swith_to_otherpage { - font-size: 15px; - width: 100%; - max-width: 592px; - margin-left: auto; - margin-right: auto; - } -} - -/* PC: 1200px 이상 */ -@media screen and (min-width: 1200px) { - main { - max-width: 640px; - padding: 0; - } - - .login_homebutton_logo { - margin-top: 60px; - margin-bottom: 40px; - } - - .login_homebutton_logo img { - width: 396px; - } - - .input_item { - margin-bottom: 24px; - width: 100%; - max-width: 640px; /* PC 최대 너비 */ - margin-left: auto; - margin-right: auto; - } - - .input_item label { - font-size: 18px; - } - - .input_item input { - padding: 16px 24px; - font-size: 16px; - line-height: 24px; - width: 100%; - } - - .input_with_icon { - width: 100%; - } - - .input_with_icon input { - padding: 16px 50px 16px 24px; /* 오른쪽 패딩을 아이콘 공간으로 설정 */ - width: 100%; - } - - .pill-button { - display: block; - font-size: 20px; - padding: 16px 0; - width: 100%; - max-width: 640px; /* PC 최대 너비 */ - margin: 0 auto; - } - - .social_login { - display: block; - padding: 16px 24px; /* .input_item input과 동일한 패딩 */ - margin: 20px 0; /* 마진 줄임 (기존 24px -> 20px) */ - width: 100%; - max-width: 640px; /* PC 최대 너비 */ - margin-left: auto; - margin-right: auto; - display: flex; - align-items: center; - justify-content: space-between; - box-sizing: border-box; - } - - .swith_to_otherpage { - font-size: 16px; - width: 100%; - max-width: 640px; - margin-left: auto; - margin-right: auto; - } -} diff --git a/mission2/login.html b/mission2/login.html deleted file mode 100644 index 94c285db..00000000 --- a/mission2/login.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - 판다마켓 - - - - - - -
- - -
-
- - -
-
- -
- - - -
-
-
- - -
-

간편 로그인하기

- -
-
- 판다마켓이 처음이신가요? 회원가입 -
-
- - diff --git a/mission2/privacy.html b/mission2/privacy.html index 0219f451..3367409c 100644 --- a/mission2/privacy.html +++ b/mission2/privacy.html @@ -6,6 +6,6 @@ Document - 임시 개인정보 약관 페이지 + 향후 작성 예정 diff --git a/mission2/signin.html b/mission2/signin.html new file mode 100644 index 00000000..98aa9c8a --- /dev/null +++ b/mission2/signin.html @@ -0,0 +1,82 @@ + + + + + + 판다마켓 - 로그인 + + + + + + + +
+ 판다마켓 홈 + +
+
+ + + +
+
+ +
+ + 비밀번호 숨김 +
+

+
+ + +
+ +
+

간편 로그인하기

+ +
+ +
+ 판다마켓이 처음이신가요? 회원가입 +
+
+ + + diff --git a/mission2/signup.html b/mission2/signup.html index a81fcd0c..c24599e3 100644 --- a/mission2/signup.html +++ b/mission2/signup.html @@ -3,32 +3,26 @@ - 판다마켓 - + 판다마켓 - 회원가입 + - - + + + -
- +
+ 판다마켓 홈
-
+
+
-
+
+

- -
+
-
+
비밀번호 숨김 상태 아이콘
+

-
- -
+
+ +
비밀번호 숨김 상태 아이콘
+

+ + - -
+ + diff --git a/mission2/styles/auth.css b/mission2/styles/auth.css new file mode 100644 index 00000000..8a20cabf --- /dev/null +++ b/mission2/styles/auth.css @@ -0,0 +1,131 @@ +.auth-container { + max-width: 400px; + margin: 0 auto; + padding: 0 16px; +} + +.logo-home-button { + margin: 0 auto; + display: block; + margin-top: 24px; + margin-bottom: 24px; + width: 198px; +} + +.logo-home-button img { + width: 100%; +} + +.input-item { + margin-bottom: 24px; + display: flex; + flex-direction: column; +} + +label { + display: block; + font-weight: 700; + font-size: 14px; + margin-bottom: 8px; +} + +input { + padding: 16px 24px; + background-color: #f3f4f6; + border: none; + border-radius: 12px; + font-size: 16px; + line-height: 24px; + width: 100%; +} + +input::placeholder { + color: #9ca3af; + font-size: 16px; + line-height: 24px; +} + +input:focus { + outline-color: var(--blue); +} + +.input-error { + border: 1px solid #ff5b56 !important; /* 빨간색 테두리 */ + background-color: #fff0f0 !important; /* 연한 빨간색 배경 */ +} + +.error-message { + color: #ff5b56; /* 빨간색 텍스트 */ + font-size: 12px; + margin-top: 4px; + min-height: 1em; /* 메시지가 없을 때도 공간을 차지하도록 */ +} + +.input-wrapper { + position: relative; + display: flex; + align-items: center; +} + +.toggle-password { + position: absolute; + right: 24px; + cursor: pointer; +} + +.social-login-container { + background-color: #e6f2ff; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 23px; + margin: 24px 0; +} + +.social-login-container h3 { + font-weight: 500; + font-size: 16px; + line-height: 24px; +} + +.social-login-buttons-container { + display: flex; + gap: 16px; +} + +.auth-switch { + font-weight: 500; + font-size: 15px; + text-align: center; +} + +.auth-switch a { + color: #3182f6; + text-decoration: underline; + text-underline-offset: 2px; +} + +@media (min-width: 768px) { + .auth-container { + max-width: 640px; + } + + .logo-home-button { + width: 396px; + margin-top: 48px; + margin-bottom: 40px; + } + + label { + font-size: 18px; + margin-bottom: 16px; + } +} + +@media (min-width: 1280px) { + .logo-home-button { + margin-top: 60px; + margin-bottom: 40px; + } +} diff --git a/mission2/styles/global.css b/mission2/styles/global.css new file mode 100644 index 00000000..26a87099 --- /dev/null +++ b/mission2/styles/global.css @@ -0,0 +1,179 @@ +:root { + /* Gray scale */ + --gray-900: #1b1d1f; + --gray-800: #26282b; + --gray-600: #454c53; + --gray-500: #72787f; + --gray-400: #9ea4a8; + --gray-200: #e5e7eb; + --gray-100: #e8ebed; + --gray-50: #f7f7f8; + + /* Primary color */ + --blue: #3692ff; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + color: #374151; + word-break: keep-all; + font-family: "Pretendard", sans-serif; +} + +header { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 70px; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 16px; + background-color: #ffffff; + border-bottom: 1px solid #dfdfdf; +} + +main { + margin-top: 70px; +} + +footer { + background-color: #111827; + padding: 32px; + font-size: 16px; + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 60px; +} + +#copyright { + order: 3; + flex-basis: 100%; + color: #9ca3af; +} + +#footerMenu { + display: flex; + gap: 30px; + color: var(--gray-200); +} + +#socialMedia { + display: flex; + gap: 12px; +} + +a { + text-decoration: none; + color: inherit; +} + +img { + vertical-align: bottom; +} + +.wrapper { + max-width: 1200px; + margin: 0 auto; + width: 100%; + padding: 0 16px; +} + +button { + background: none; + border: none; + outline: none; + box-shadow: none; + cursor: pointer; + font-family: inherit; + font-size: inherit; + line-height: inherit; + color: inherit; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.button { + background-color: var(--blue); + color: #ffffff; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.button:hover { + background-color: #1967d6; +} + +.button:focus { + background-color: #1251aa; +} + +.button:disabled { + background-color: #9ca3af; + cursor: default; + pointer-events: none; +} + +.pill-button { + font-size: 16px; + font-weight: 600; + border-radius: 999px; + padding: 14.5px 33.5px; +} + +.full-width { + width: 100%; +} + +.break-on-desktop { + display: none; +} + +@media (min-width: 768px) { + header { + padding: 0 24px; + } + + .wrapper { + padding: 0 24px; + } + + .pill-button { + font-size: 20px; + font-weight: 700; + padding: 16px 126px; + } + + footer { + padding: 32px 104px 108px 104px; + } + + #copyright { + flex-basis: auto; + order: 0; + } +} + +@media (min-width: 1280px) { + header { + padding: 0 200px; + } + + .break-on-desktop { + display: inline; + } + + footer { + padding: 32px 200px 108px 200px; + } +} diff --git a/mission2/styles/home.css b/mission2/styles/home.css new file mode 100644 index 00000000..97420bf9 --- /dev/null +++ b/mission2/styles/home.css @@ -0,0 +1,164 @@ +.banner { + background-color: #cfe5ff; + height: 60vh; + text-align: center; + background-repeat: no-repeat; + background-position: bottom; + background-size: 130%; +} + +#hero { + background-image: url("../images/home/hero-image.png"); +} + +.banner h1 { + font-weight: 700; + font-size: 32px; + line-height: 44.8px; + padding-top: 48px; + padding-bottom: 18px; +} + +#bottomBanner { + background-image: url("../images/home/bottom-banner-image.png"); +} + +#signinLinkButton { + font-size: 16px; + font-weight: 600; + border-radius: 8px; + padding: 14.5px 43px; +} + +#features { + padding-top: 51px; +} + +.feature { + margin-bottom: 64px; +} + +.feature img { + width: 100%; + margin-bottom: 20px; +} + +.feature:nth-child(2) { + text-align: right; +} + +.feature-content { + flex: 1; +} + +.feature-content h2 { + color: var(--blue); + font-size: 16px; + line-height: 22.4px; + font-weight: 700; + margin-bottom: 8px; +} + +.feature-content h1 { + font-weight: 700; + font-size: 24px; + line-height: 33.6px; +} + +.feature-description { + font-weight: 500; + font-size: 16px; + line-height: 19.2px; + letter-spacing: 0.08em; + margin-top: 20px; +} + +@media (min-width: 768px) { + .banner { + height: 90vh; + background-size: 120%; + } + + .banner h1 { + font-size: 40px; + line-height: 56px; + padding-top: 84px; + padding-bottom: 24px; + } + + #hero h1 br { + display: none; + } + + #features { + padding-top: 24px; + padding-bottom: 16px; + } + + .feature-content h2 { + font-size: 18px; + line-height: 25.2px; + margin-bottom: 12px; + } + + .feature-content h1 { + font-size: 32px; + line-height: 44.8px; + } + + .feature-description { + font-size: 18px; + line-height: 21.6px; + } +} + +@media (min-width: 1280px) { + .banner { + text-align: left; + height: 540px; + display: flex; + align-items: center; + background-position: 80% bottom; + background-size: 55%; + } + + .banner h1 { + padding-top: 0; + padding-bottom: 32px; + } + + #hero h1 br { + display: inline; + } + + #features { + padding: 138px 0; + } + + .feature { + margin-bottom: 138px; + display: flex; + align-items: center; + gap: 5%; + } + + .feature:nth-child(2) { + flex-direction: row-reverse; + } + + .feature img { + width: 50%; + margin-bottom: 0; + } + + .feature-content h1 { + font-size: 40px; + line-height: 56px; + } + + .feature-description { + font-size: 24px; + line-height: 28.8px; + margin-top: 24px; + } +}