diff --git a/faq.html b/faq.html new file mode 100644 index 00000000..e69de29b diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100644 index 00000000..32b7375f Binary files /dev/null and b/img/favicon.ico differ diff --git a/img/home/facebook-icon.png b/img/home/facebook-icon.png new file mode 100644 index 00000000..93506ba7 Binary files /dev/null and b/img/home/facebook-icon.png differ diff --git a/img/home/instagram-icon.png b/img/home/instagram-icon.png new file mode 100644 index 00000000..8a15c43f Binary files /dev/null and b/img/home/instagram-icon.png differ diff --git a/img/home/main-img-1.png b/img/home/main-img-1.png new file mode 100644 index 00000000..a5523b45 Binary files /dev/null and b/img/home/main-img-1.png differ diff --git a/img/home/main-img-2.png b/img/home/main-img-2.png new file mode 100644 index 00000000..437e317b Binary files /dev/null and b/img/home/main-img-2.png differ diff --git a/img/home/main-img-3.png b/img/home/main-img-3.png new file mode 100644 index 00000000..477cbfe5 Binary files /dev/null and b/img/home/main-img-3.png differ diff --git a/img/home/panda-image-bottom.png b/img/home/panda-image-bottom.png new file mode 100644 index 00000000..93f4fb64 Binary files /dev/null and b/img/home/panda-image-bottom.png differ diff --git a/img/home/panda-image-top.png b/img/home/panda-image-top.png new file mode 100644 index 00000000..20edcf6a Binary files /dev/null and b/img/home/panda-image-top.png differ diff --git a/img/home/twitter-icon.png b/img/home/twitter-icon.png new file mode 100644 index 00000000..1d0aa671 Binary files /dev/null and b/img/home/twitter-icon.png differ diff --git a/img/home/youtube-icon.png b/img/home/youtube-icon.png new file mode 100644 index 00000000..53df4e6e Binary files /dev/null and b/img/home/youtube-icon.png differ diff --git a/img/login/btn_visibility_off.png b/img/login/btn_visibility_off.png new file mode 100644 index 00000000..ebcfa294 Binary files /dev/null and b/img/login/btn_visibility_off.png differ diff --git a/img/login/btn_visibility_on.png b/img/login/btn_visibility_on.png new file mode 100644 index 00000000..7ef100fd Binary files /dev/null and b/img/login/btn_visibility_on.png differ diff --git a/img/login/google_logo.png b/img/login/google_logo.png new file mode 100644 index 00000000..75d2daa9 Binary files /dev/null and b/img/login/google_logo.png differ diff --git a/img/login/kakao_logo.png b/img/login/kakao_logo.png new file mode 100644 index 00000000..6e8343ea Binary files /dev/null and b/img/login/kakao_logo.png differ diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 00000000..41e594cd Binary files /dev/null and b/img/logo.png differ diff --git a/img/text-logo.png b/img/text-logo.png new file mode 100644 index 00000000..7e94a17d Binary files /dev/null and b/img/text-logo.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..c4862417 --- /dev/null +++ b/index.html @@ -0,0 +1,186 @@ + + + + + + + + + + + + + 판다 마켓 + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+

+ 일상의 모든 물건을 +
+ 거래해 보세요 +

+ 구경하러 가기 +
+ 귀여운 판다 한마리가 서있는 이미지 +
+
+
+
+ 인기 있는 옷을 바라보는 판다 두마리의 뒷모습 +
+
Hot item
+
+ 인기 상품을 +
+ 확인해 보세요 +
+

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

+
+
+
+
+ +
+
+
+ 연필, 필통, 도서, 안경 같은 물건을 등록하는 이미지 +
+
Register
+
+ 판매를 원하는 +
+ 상품을 등록하세요 +
+

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

+
+
+
+
+
+
+

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

+
+ 귀여운 판다 두마리가 중고 거래하는 이미지 +
+
+
+ + + + diff --git a/items.html b/items.html new file mode 100644 index 00000000..e69de29b diff --git a/js/common.js b/js/common.js new file mode 100644 index 00000000..2fac942e --- /dev/null +++ b/js/common.js @@ -0,0 +1,46 @@ +/* 에러 메시지 처리 */ +function wrongInput(input, span, validateFunction) { + const errorMessage = validateFunction(input); + if (errorMessage) { + input.classList.add("warning"); + input.classList.remove("done"); + span.textContent = errorMessage; + } else { + input.classList.remove("warning"); + input.classList.add("done"); + span.textContent = ""; + } + input.parentElement.appendChild(span); + if (span.textContent === "") { + input.parentElement.removeChild(span); + } +} + +/* 눈모양 버튼 클릭시 비밀번호 보이기 / 가리기 */ +function togglePasswordVisibility(button) { + const passwordInput = button.previousElementSibling; + if (passwordInput.type === "password") { + passwordInput.type = "text"; + button.classList.add("visible"); + } else { + passwordInput.type = "password"; + button.classList.remove("visible"); + } +} + +/* inputs에 모두 done 클래스가 있다면 버튼 활성화 */ +function activateButton(button, inputs) { + if (inputs.every((input) => input.classList.contains("done"))) { + button.disabled = false; + } else { + button.disabled = true; + } +} + +// 버튼 클릭시 특정 페이지로 이동 +function redirectToPage(event, redirectUrl) { + event.preventDefault(); + window.location.href = redirectUrl; +} + +export { wrongInput, togglePasswordVisibility, activateButton, redirectToPage }; diff --git a/js/login.js b/js/login.js new file mode 100644 index 00000000..2c6b7be3 --- /dev/null +++ b/js/login.js @@ -0,0 +1,76 @@ +import { + wrongInput, + togglePasswordVisibility, + activateButton, + redirectToPage, +} from "./common.js"; + +const emailInput = document.querySelector("#input-email"); +const passwordInput = document.querySelector("#input-password"); +const loginButton = document.querySelector(".login-page .submit-button"); +const loginForm = document.querySelector(".login-page .form-container"); + +const wrongEmail = document.createElement("span"); +const wrongPassword = document.createElement("span"); + +const inputArray = [emailInput, passwordInput]; + +wrongEmail.classList.add("error-message"); +wrongPassword.classList.add("error-message"); + +loginButton.disabled = true; + +function validateEmail(input) { + if (input.value === "") { + return "이메일을 입력해주세요."; + } else if (!input.checkValidity()) { + return "잘못된 이메일 형식입니다."; + } +} + +function validatePassword(input) { + if (input.value === "") { + return "비밀번호를 입력해주세요."; + } else if (input.value.length < 8) { + return "비밀번호를 8자 이상 입력해주세요."; + } +} + +/* email 에러 메시지 처리 */ +emailInput.addEventListener("focusout", () => + wrongInput(emailInput, wrongEmail, validateEmail) +); +emailInput.addEventListener("input", () => + wrongInput(emailInput, wrongEmail, validateEmail) +); + +/* password 에러 메시지 처리 */ +passwordInput.addEventListener("focusout", () => + wrongInput(passwordInput, wrongPassword, validatePassword) +); +passwordInput.addEventListener("input", () => + wrongInput(passwordInput, wrongPassword, validatePassword) +); + +/* email, password에 유효한 값이 입력되면 로그인 페이지 버튼 활성화 */ +inputArray.forEach((input) => { + input.addEventListener("input", () => + activateButton(loginButton, inputArray) + ); +}); + +inputArray.forEach((input) => { + input.addEventListener("focusout", () => + activateButton(loginButton, inputArray) + ); +}); + +/* 로그인 버튼 클릭시 items 페이지로 이동 */ +loginForm.addEventListener("submit", (event) => + redirectToPage(event, "/items.html") +); + +/* 눈모양 버튼 클릭시 */ +document.querySelectorAll(".visibility").forEach((button) => { + button.addEventListener("click", () => togglePasswordVisibility(button)); +}); diff --git a/js/signup.js b/js/signup.js new file mode 100644 index 00000000..b1895b92 --- /dev/null +++ b/js/signup.js @@ -0,0 +1,125 @@ +import { + wrongInput, + togglePasswordVisibility, + activateButton, + redirectToPage, +} from "./common.js"; + +const emailInput = document.querySelector("#input-email"); +const nicknameInput = document.querySelector("#input-nickname"); +const passwordInput = document.querySelector("#input-password"); +const passwordCheckInput = document.querySelector("#input-password-check"); +const signupButton = document.querySelector(".signup-page .submit-button"); +const signupForm = document.querySelector(".signup-page .form-container"); + +const wrongEmail = document.createElement("span"); +const wrongNickname = document.createElement("span"); +const wrongPassword = document.createElement("span"); +const wrongpasswordCheck = document.createElement("span"); + +const inputArray = [ + emailInput, + nicknameInput, + passwordInput, + passwordCheckInput, +]; + +wrongEmail.classList.add("error-message"); +wrongNickname.classList.add("error-message"); +wrongPassword.classList.add("error-message"); +wrongpasswordCheck.classList.add("error-message"); + +signupButton.disabled = true; + +function validateEmail(input) { + if (input.value === "") { + return "이메일을 입력해주세요."; + } else if (!input.checkValidity()) { + return "잘못된 이메일 형식입니다."; + } +} + +function validateNickname(input) { + if (input.value === "") { + return "닉네임을 입력해주세요."; + } +} + +function validatePassword(input) { + if (input.value === "") { + return "비밀번호를 입력해주세요."; + } else if (input.value.length < 8) { + return "비밀번호를 8자 이상 입력해주세요."; + } +} + +function wrongPasswordCheckEvent() { + if (passwordCheckInput.value === "") { + wrongpasswordCheck.textContent = ""; + passwordCheckInput.classList.remove("warning", "done"); + } else if (passwordCheckInput.value !== passwordInput.value) { + passwordCheckInput.classList.add("warning"); + passwordCheckInput.classList.remove("done"); + wrongpasswordCheck.textContent = "비밀번호가 일치하지 않습니다."; + } else { + passwordCheckInput.classList.remove("warning"); + passwordCheckInput.classList.add("done"); + wrongpasswordCheck.textContent = ""; + } + passwordCheckInput.parentElement.appendChild(wrongpasswordCheck); + if (wrongpasswordCheck.textContent === "") { + passwordCheckInput.parentElement.removeChild(wrongpasswordCheck); + } +} + +/* email 에러 메시지 처리 */ +emailInput.addEventListener("focusout", () => + wrongInput(emailInput, wrongEmail, validateEmail) +); +emailInput.addEventListener("input", () => + wrongInput(emailInput, wrongEmail, validateEmail) +); + +/* nickname 에러 메시지 처리 */ +nicknameInput.addEventListener("focusout", () => + wrongInput(nicknameInput, wrongNickname, validateNickname) +); +nicknameInput.addEventListener("input", () => + wrongInput(nicknameInput, wrongNickname, validateNickname) +); + +/* password 에러 메시지 처리 */ +passwordInput.addEventListener("focusout", () => + wrongInput(passwordInput, wrongPassword, validatePassword) +); +passwordInput.addEventListener("input", () => + wrongInput(passwordInput, wrongPassword, validatePassword) +); + +/* password-check 에러 메시지 처리 */ +passwordInput.addEventListener("input", wrongPasswordCheckEvent); // password가 변경되어도 즉시 password-check과 비교 +passwordCheckInput.addEventListener("focusout", wrongPasswordCheckEvent); +passwordCheckInput.addEventListener("input", wrongPasswordCheckEvent); + +/* email, nickname, password, password-check에 유효한 값이 입력되면 회원가입 페이지 버튼 활성화 */ +inputArray.forEach((input) => { + input.addEventListener("input", () => + activateButton(signupButton, inputArray) + ); +}); + +inputArray.forEach((input) => { + input.addEventListener("focusout", () => + activateButton(signupButton, inputArray) + ); +}); + +/* 회원가입 버튼 클릭시 로그인 페이지로 이동 */ +signupForm.addEventListener("submit", (event) => + redirectToPage(event, "/login.html") +); + +/* 눈모양 버튼 클릭시 */ +document.querySelectorAll(".visibility").forEach((button) => { + button.addEventListener("click", () => togglePasswordVisibility(button)); +}); diff --git a/login.html b/login.html new file mode 100644 index 00000000..13caa5f4 --- /dev/null +++ b/login.html @@ -0,0 +1,82 @@ + + + + + + + + + + + 로그인 + + + + +
+
+
+ + +
+ +
+ + +
+
+ + +
+
+
+

간편 로그인하기

+ +
+
+

판다마켓이 처음이신가요?

+ 회원가입 +
+ + +
+ + diff --git a/privacy.html b/privacy.html new file mode 100644 index 00000000..e69de29b diff --git a/signup.html b/signup.html new file mode 100644 index 00000000..d46f7f8a --- /dev/null +++ b/signup.html @@ -0,0 +1,104 @@ + + + + + + + + + + + 회원가입 + + + + +
+
+
+ +
+ +
+ +
+
+
+ +
+ + +
+
+ +
+ +
+ + +
+
+ + +
+
+
+

간편 로그인하기

+ +
+
+

이미 회원이신가요?

+ 로그인 +
+
+ + + diff --git a/style/auth.css b/style/auth.css new file mode 100644 index 00000000..6f06905f --- /dev/null +++ b/style/auth.css @@ -0,0 +1,174 @@ +.login-page, +.signup-page { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + min-height: 100vh; +} + +.page-header { + display: flex; + justify-content: center; + padding-bottom: 4rem; + max-width: 64rem; +} + +.logo { + width: 40rem; +} + +.page-main { + width: 64rem; +} + +.form-container, +.email-container, +.nickname-container, +.password-container, +.password-check-container { + display: flex; + flex-direction: column; +} + +.form-container { + gap: 2.4rem; +} + +.form-container label { + font-size: 1.8rem; + font-weight: 700; + line-height: 2.6rem; +} + +.form-container input { + height: 5.6rem; + border: none; + border-radius: 12px; + background-color: var(--gray100); + padding: 1.6rem 2.4rem; +} + +.form-container input::placeholder { + font-size: 16px; + font-weight: 400; + line-height: 26px; + color: var(--gray400); +} + +.email-container, +.nickname-container, +.password-container, +.password-check-container { + gap: 1.6rem; +} + +.email-input input, +.nickname-input input { + width: 100%; +} + +.password-input { + position: relative; +} + +.password-input input { + width: 100%; + padding-right: 4.8rem; +} + +.form-container .warning { + border: 1px solid var(--red); +} + +.error-message { + display: inline-block; + margin-left: 16px; + margin-top: 8px; + font-size: 14px; + font-weight: 600; + line-height: 24px; + color: var(--red); +} + +.visibility { + position: absolute; + right: 2.4rem; + top: 1.6rem; + width: 2.4rem; + height: 2.4rem; + border: none; + background-image: url("../img/login/btn_visibility_off.png"); + background-size: cover; + background-color: transparent; +} + +.visible { + background-image: url("../img/login/btn_visibility_on.png"); +} + +.submit-button { + height: 5.6rem; + border: none; + border-radius: 40px; + background-color: var(--blue100); + color: var(--gray100); + font-size: 2rem; + font-weight: 600; + line-height: 3.2rem; +} + +.submit-button:disabled { + background-color: var(--gray400); +} + +.social-login { + background-color: #e6f2ff; + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.6rem 2.3rem; + margin-top: 2.4rem; + font-size: 1.6rem; + font-weight: 500; + line-height: 2.6rem; + border-radius: 8px; +} + +.social-list { + display: flex; + gap: 1.6rem; +} + +.social-list a { + display: flex; +} + +.social-list img { + width: 4.2rem; +} + +.ask-section { + display: flex; + justify-content: center; + margin-top: 2.4rem; + font-size: 1.4rem; + font-weight: 500; + line-height: 2.4rem; + gap: 0.4rem; +} + +.ask-section a { + color: #3692ff; + text-decoration: underline; +} + +/* Mobile: 375px 이상 ~ 767px 이하 */ +@media screen and (max-width: 767px) { + .logo, + .page-main { + width: calc(100vw - 32px); + max-width: 400px; + margin: 0 auto; + } +} diff --git a/style/base.css b/style/base.css new file mode 100644 index 00000000..b6a4c6bc --- /dev/null +++ b/style/base.css @@ -0,0 +1,24 @@ +:root { + --gray50: #f9fafb; + --gray100: #f3f4f6; + --gray200: #e5e7eb; + --gray400: #9ca3af; + --gray500: #6b7280; + --gray600: #4b5563; + --gray700: #374151; + --gray800: #1f2937; + --gray900: #111827; + --blue100: #3692ff; + --blue200: #1967d6; + --blue300: #1251aa; + --red: #f74747; +} + +* { + box-sizing: border-box; +} + +html { + font-family: "Pretendard", sans-serif; + font-size: 62.5%; +} diff --git a/style/home.css b/style/home.css new file mode 100644 index 00000000..a2d31908 --- /dev/null +++ b/style/home.css @@ -0,0 +1,184 @@ +nav { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 200px; + height: 70px; + background-color: rgba(255, 255, 255, 0.9); + position: fixed; + top: 0; + width: 100%; + z-index: 100; +} + +.logo { + display: flex; + align-items: center; + height: 51px; +} + +.login-link { + font-size: 1.6rem; + font-weight: 600; + color: #ffffff; + background-color: var(--blue100); + border-radius: 8px; + padding: 12px 23px; +} + +.top-section, +.bottom-section { + margin-top: 70px; + background-color: #cfe5ff; + height: 540px; + display: flex; + align-items: flex-end; + justify-content: center; + overflow: hidden; +} + +.bottom-section { + margin-top: 138px; +} + +.top-section img { + width: 746px; + height: 340px; +} + +.bottom-section img { + width: 746px; + height: 397px; +} + +.top-section-container { + display: flex; + align-items: center; + gap: 7px; +} + +.bottom-section-container { + display: flex; + align-items: center; + gap: 69px; +} + +.top-section-text, +.bottom-section-text { + padding-bottom: 60px; +} + +.top-section-text p, +.bottom-section-text p { + font-size: 4rem; + font-weight: 700; + line-height: 5.6rem; + color: var(--gray700); +} + +.top-section-text a { + font-size: 2rem; + font-weight: 600; + color: #ffffff; + background-color: var(--blue100); + padding: 16px 124px; + border-radius: 40px; + margin-top: 3.2rem; + display: inline-block; +} + +.main-section { + display: flex; + align-items: center; + justify-content: center; + padding: 138px 0; +} + +.hot-item, +.search, +.register { + display: flex; + align-items: center; + gap: 64px; + background-color: #fcfcfc; + border-radius: 12px; +} + +.text-container { + display: flex; + flex-direction: column; + gap: 12px; +} + +.hot-item .text-container, +.register .text-container { + padding-right: 24px; +} + +.search .text-container { + padding-left: 24px; +} + +.small-text { + font-size: 1.8rem; + font-weight: 700; + line-height: 5.6rem; + color: var(--blue100); +} + +.big-text { + font-size: 4rem; + font-weight: 700; + line-height: 5.6rem; + color: var(--gray700); +} + +.main-section p { + font-size: 2.4rem; + font-weight: 500; + line-height: 3.2rem; + margin-top: 1rem; + color: var(--gray700); +} + +.main-section img { + width: 579px; + height: 444px; +} + +footer { + background-color: var(--gray900); + height: 160px; + padding: 32px 400px; + display: flex; + justify-content: space-between; +} + +.codeit { + font-size: 16px; + font-weight: 400; + line-height: 19px; + color: var(--gray400); +} + +.footer-center { + display: flex; + gap: 30px; + font-size: 16px; + font-weight: 400; + line-height: 19px; + color: var(--gray200); +} + +.footer-right a { + margin-right: 12px; +} + +.footer-right a:last-child { + margin: 0; +} + +.footer-right img { + width: 20px; + height: 20px; +} diff --git a/style/home_media.css b/style/home_media.css new file mode 100644 index 00000000..f94126ac --- /dev/null +++ b/style/home_media.css @@ -0,0 +1,169 @@ +/* Tablet: 1199px 까지 적용 */ +@media screen and (max-width: 1199px) { + html { + font-size: 8px; + } + + nav { + padding: 0 24px; + } + + .top-section { + height: 771px; + } + + .top-section-container { + flex-direction: column; + gap: 141px; + } + + .top-section-text { + display: flex; + flex-direction: column; + align-items: center; + } + + .top-section img, + .bottom-section img { + height: auto; + width: 744px; + } + + .top-section p br, + .big-text br { + display: none; + } + + .main-section { + padding: 26px; + } + + .main-section img { + width: 696px; + height: auto; + } + + .hot-item, + .register { + flex-direction: column; + align-items: flex-start; + gap: 0; + } + .search { + flex-direction: column-reverse; + align-items: flex-end; + gap: 0; + } + + .search .text-container { + align-items: flex-end; + } + + .search .text-container p { + text-align: end; + } + + .bottom-section { + height: 927px; + margin-top: 26px; + } + + .bottom-section-container { + flex-direction: column; + gap: 160px; + } + + .bottom-section-text { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + } + + footer { + padding: 32px 104px; + } +} + +/* Mobile: 767px 이하까지 적용 */ +@media screen and (max-width: 767px) { + html { + font-size: 6px; + } + + nav { + padding: 0 16px; + } + + .top-section { + height: 540px; + } + + .top-section-container { + flex-direction: column; + gap: 62px; + } + + .top-section-text { + text-align: center; + } + + .top-section p br { + display: inline; + } + + .top-section-text a { + padding: 12px 71px; + } + + .top-section img { + height: auto; + width: 448px; + } + + .bottom-section img { + height: auto; + width: 375px; + } + + .main-section { + padding: 20px; + } + + .main-section img { + width: 344px; + height: auto; + } + + .bottom-section { + height: 540px; + margin-top: 3.25rem; + } + + .bottom-section-container { + flex-direction: column; + gap: 61px; + } + footer { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: auto auto; + gap: 10px; + padding: 32px; + } + + .codeit { + grid-column: 1 / -1; + grid-row: 2; + align-self: end; + } + + .footer-center { + grid-column: 1; + } + + .footer-right { + grid-column: 2; + justify-self: end; + } +} diff --git a/style/reset.css b/style/reset.css new file mode 100644 index 00000000..f43a0980 --- /dev/null +++ b/style/reset.css @@ -0,0 +1,139 @@ +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +a { + text-decoration: none; + color: inherit; +} + +button { + cursor: pointer; +} + +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} + +body { + line-height: 1; +} + +ol, +ul { + list-style: none; +} + +blockquote, +q { + quotes: none; +} + +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ""; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +}