From 2ad43e98fbb0a42198ad62a1c243af7e71788a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9A=B0=EC=84=B1?= Date: Fri, 14 Jun 2024 20:15:14 +0900 Subject: [PATCH] fixed: recreate sprint mission --- sprint/.gitignore | 1 + .../banner_bottom/1x.png} | Bin .../banner_bottom/3x.png} | Bin .../banner_bottom/4x.png} | Bin .../banner_top/1x.png} | Bin .../banner_top/3x.png} | Bin .../banner_top/4x.png} | Bin .../contents/01/1x.png} | Bin .../contents/01/3x.png} | Bin .../contents/01/4x.png} | Bin .../contents/02/1x.png} | Bin .../contents/02/3x.png} | Bin .../contents/02/4x.png} | Bin .../contents/03/1x.png} | Bin .../contents/03/3x.png} | Bin .../contents/03/4x.png} | Bin sprint/assets/logo_facebook.svg | 3 - sprint/assets/logo_none_txt.svg | 14 - sprint/assets/svg/ic_facebook.svg | 3 + .../ic_google.svg} | 0 .../ic_instagram.svg} | 0 .../ic_kakaotalk.svg} | 0 sprint/assets/svg/ic_panda.svg | 14 + .../ic_visibility_off.svg} | 0 .../ic_visibility_on.svg} | 0 .../assets/{logo_twitter.svg => svg/ic_x.svg} | 0 .../{logo_youtube.svg => svg/ic_youtube.svg} | 4 +- .../{logo_with_txt.svg => svg/logo.svg} | 0 sprint/component.css | 53 ---- sprint/index.css | 187 ------------ sprint/index.html | 146 +-------- sprint/main.css | 217 +++++++++++++ sprint/main.js | 28 ++ sprint/src/Login.css | 117 ------- sprint/src/Login.html | 57 ---- sprint/src/Root.js | 13 + sprint/src/constant/Event.js | 109 +++++++ sprint/src/constant/ID.js | 11 + sprint/src/constant/Message.js | 18 ++ sprint/src/constant/Regex.js | 5 + sprint/src/pages/Home.css | 289 ++++++++++++++++++ sprint/src/pages/Home.js | 149 +++++++++ sprint/src/pages/sign/In.css | 73 +++++ sprint/src/pages/sign/In.js | 99 ++++++ sprint/src/pages/sign/Up.css | 76 +++++ sprint/src/pages/sign/Up.js | 129 ++++++++ sprint/src/utils/CustomElement.js | 22 ++ sprint/src/utils/CustomRouter.js | 30 ++ 48 files changed, 1292 insertions(+), 575 deletions(-) create mode 100644 sprint/.gitignore rename sprint/assets/{banner_bottom@1x.png => img/banner_bottom/1x.png} (100%) rename sprint/assets/{banner_bottom@3x.png => img/banner_bottom/3x.png} (100%) rename sprint/assets/{banner_bottom@4x.png => img/banner_bottom/4x.png} (100%) rename sprint/assets/{banner_top@1x.png => img/banner_top/1x.png} (100%) rename sprint/assets/{banner_top@3x.png => img/banner_top/3x.png} (100%) rename sprint/assets/{banner_top@4x.png => img/banner_top/4x.png} (100%) rename sprint/assets/{main_01@1x.png => img/contents/01/1x.png} (100%) rename sprint/assets/{main_01@3x.png => img/contents/01/3x.png} (100%) rename sprint/assets/{main_01@4x.png => img/contents/01/4x.png} (100%) rename sprint/assets/{main_02@1x.png => img/contents/02/1x.png} (100%) rename sprint/assets/{main_02@3x.png => img/contents/02/3x.png} (100%) rename sprint/assets/{main_02@4x.png => img/contents/02/4x.png} (100%) rename sprint/assets/{main_03@1x.png => img/contents/03/1x.png} (100%) rename sprint/assets/{main_03@3x.png => img/contents/03/3x.png} (100%) rename sprint/assets/{main_03@4x.png => img/contents/03/4x.png} (100%) delete mode 100644 sprint/assets/logo_facebook.svg delete mode 100644 sprint/assets/logo_none_txt.svg create mode 100644 sprint/assets/svg/ic_facebook.svg rename sprint/assets/{login_google_logo.svg => svg/ic_google.svg} (100%) rename sprint/assets/{logo_instagram.svg => svg/ic_instagram.svg} (100%) rename sprint/assets/{login_kakaotalk_logo.svg => svg/ic_kakaotalk.svg} (100%) create mode 100644 sprint/assets/svg/ic_panda.svg rename sprint/assets/{icon_visibility_off.svg => svg/ic_visibility_off.svg} (100%) rename sprint/assets/{icon_visibility_on.svg => svg/ic_visibility_on.svg} (100%) rename sprint/assets/{logo_twitter.svg => svg/ic_x.svg} (100%) rename sprint/assets/{logo_youtube.svg => svg/ic_youtube.svg} (93%) rename sprint/assets/{logo_with_txt.svg => svg/logo.svg} (100%) delete mode 100644 sprint/component.css delete mode 100644 sprint/index.css create mode 100644 sprint/main.css create mode 100644 sprint/main.js delete mode 100644 sprint/src/Login.css delete mode 100644 sprint/src/Login.html create mode 100644 sprint/src/Root.js create mode 100644 sprint/src/constant/Event.js create mode 100644 sprint/src/constant/ID.js create mode 100644 sprint/src/constant/Message.js create mode 100644 sprint/src/constant/Regex.js create mode 100644 sprint/src/pages/Home.css create mode 100644 sprint/src/pages/Home.js create mode 100644 sprint/src/pages/sign/In.css create mode 100644 sprint/src/pages/sign/In.js create mode 100644 sprint/src/pages/sign/Up.css create mode 100644 sprint/src/pages/sign/Up.js create mode 100644 sprint/src/utils/CustomElement.js create mode 100644 sprint/src/utils/CustomRouter.js diff --git a/sprint/.gitignore b/sprint/.gitignore new file mode 100644 index 000000000..600d2d33b --- /dev/null +++ b/sprint/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/sprint/assets/banner_bottom@1x.png b/sprint/assets/img/banner_bottom/1x.png similarity index 100% rename from sprint/assets/banner_bottom@1x.png rename to sprint/assets/img/banner_bottom/1x.png diff --git a/sprint/assets/banner_bottom@3x.png b/sprint/assets/img/banner_bottom/3x.png similarity index 100% rename from sprint/assets/banner_bottom@3x.png rename to sprint/assets/img/banner_bottom/3x.png diff --git a/sprint/assets/banner_bottom@4x.png b/sprint/assets/img/banner_bottom/4x.png similarity index 100% rename from sprint/assets/banner_bottom@4x.png rename to sprint/assets/img/banner_bottom/4x.png diff --git a/sprint/assets/banner_top@1x.png b/sprint/assets/img/banner_top/1x.png similarity index 100% rename from sprint/assets/banner_top@1x.png rename to sprint/assets/img/banner_top/1x.png diff --git a/sprint/assets/banner_top@3x.png b/sprint/assets/img/banner_top/3x.png similarity index 100% rename from sprint/assets/banner_top@3x.png rename to sprint/assets/img/banner_top/3x.png diff --git a/sprint/assets/banner_top@4x.png b/sprint/assets/img/banner_top/4x.png similarity index 100% rename from sprint/assets/banner_top@4x.png rename to sprint/assets/img/banner_top/4x.png diff --git a/sprint/assets/main_01@1x.png b/sprint/assets/img/contents/01/1x.png similarity index 100% rename from sprint/assets/main_01@1x.png rename to sprint/assets/img/contents/01/1x.png diff --git a/sprint/assets/main_01@3x.png b/sprint/assets/img/contents/01/3x.png similarity index 100% rename from sprint/assets/main_01@3x.png rename to sprint/assets/img/contents/01/3x.png diff --git a/sprint/assets/main_01@4x.png b/sprint/assets/img/contents/01/4x.png similarity index 100% rename from sprint/assets/main_01@4x.png rename to sprint/assets/img/contents/01/4x.png diff --git a/sprint/assets/main_02@1x.png b/sprint/assets/img/contents/02/1x.png similarity index 100% rename from sprint/assets/main_02@1x.png rename to sprint/assets/img/contents/02/1x.png diff --git a/sprint/assets/main_02@3x.png b/sprint/assets/img/contents/02/3x.png similarity index 100% rename from sprint/assets/main_02@3x.png rename to sprint/assets/img/contents/02/3x.png diff --git a/sprint/assets/main_02@4x.png b/sprint/assets/img/contents/02/4x.png similarity index 100% rename from sprint/assets/main_02@4x.png rename to sprint/assets/img/contents/02/4x.png diff --git a/sprint/assets/main_03@1x.png b/sprint/assets/img/contents/03/1x.png similarity index 100% rename from sprint/assets/main_03@1x.png rename to sprint/assets/img/contents/03/1x.png diff --git a/sprint/assets/main_03@3x.png b/sprint/assets/img/contents/03/3x.png similarity index 100% rename from sprint/assets/main_03@3x.png rename to sprint/assets/img/contents/03/3x.png diff --git a/sprint/assets/main_03@4x.png b/sprint/assets/img/contents/03/4x.png similarity index 100% rename from sprint/assets/main_03@4x.png rename to sprint/assets/img/contents/03/4x.png diff --git a/sprint/assets/logo_facebook.svg b/sprint/assets/logo_facebook.svg deleted file mode 100644 index 3a24fb4bf..000000000 --- a/sprint/assets/logo_facebook.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/sprint/assets/logo_none_txt.svg b/sprint/assets/logo_none_txt.svg deleted file mode 100644 index afe3b9841..000000000 --- a/sprint/assets/logo_none_txt.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/sprint/assets/svg/ic_facebook.svg b/sprint/assets/svg/ic_facebook.svg new file mode 100644 index 000000000..8491c2f83 --- /dev/null +++ b/sprint/assets/svg/ic_facebook.svg @@ -0,0 +1,3 @@ + + + diff --git a/sprint/assets/login_google_logo.svg b/sprint/assets/svg/ic_google.svg similarity index 100% rename from sprint/assets/login_google_logo.svg rename to sprint/assets/svg/ic_google.svg diff --git a/sprint/assets/logo_instagram.svg b/sprint/assets/svg/ic_instagram.svg similarity index 100% rename from sprint/assets/logo_instagram.svg rename to sprint/assets/svg/ic_instagram.svg diff --git a/sprint/assets/login_kakaotalk_logo.svg b/sprint/assets/svg/ic_kakaotalk.svg similarity index 100% rename from sprint/assets/login_kakaotalk_logo.svg rename to sprint/assets/svg/ic_kakaotalk.svg diff --git a/sprint/assets/svg/ic_panda.svg b/sprint/assets/svg/ic_panda.svg new file mode 100644 index 000000000..2637dd6ef --- /dev/null +++ b/sprint/assets/svg/ic_panda.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/sprint/assets/icon_visibility_off.svg b/sprint/assets/svg/ic_visibility_off.svg similarity index 100% rename from sprint/assets/icon_visibility_off.svg rename to sprint/assets/svg/ic_visibility_off.svg diff --git a/sprint/assets/icon_visibility_on.svg b/sprint/assets/svg/ic_visibility_on.svg similarity index 100% rename from sprint/assets/icon_visibility_on.svg rename to sprint/assets/svg/ic_visibility_on.svg diff --git a/sprint/assets/logo_twitter.svg b/sprint/assets/svg/ic_x.svg similarity index 100% rename from sprint/assets/logo_twitter.svg rename to sprint/assets/svg/ic_x.svg diff --git a/sprint/assets/logo_youtube.svg b/sprint/assets/svg/ic_youtube.svg similarity index 93% rename from sprint/assets/logo_youtube.svg rename to sprint/assets/svg/ic_youtube.svg index 50f5648f0..249006a0b 100644 --- a/sprint/assets/logo_youtube.svg +++ b/sprint/assets/svg/ic_youtube.svg @@ -1,9 +1,9 @@ - + - + diff --git a/sprint/assets/logo_with_txt.svg b/sprint/assets/svg/logo.svg similarity index 100% rename from sprint/assets/logo_with_txt.svg rename to sprint/assets/svg/logo.svg diff --git a/sprint/component.css b/sprint/component.css deleted file mode 100644 index acce52ed1..000000000 --- a/sprint/component.css +++ /dev/null @@ -1,53 +0,0 @@ -:root { - --gray-scale-900: #111827; - --gray-scale-800: #1f2937; - --gray-scale-700: #374151; - --gray-scale-600: #4b5563; - --gray-scale-500: #6b7280; - --gray-scale-400: #9ca3af; - --gray-scale-200: #e5e7eb; - --gray-scale-100: #f3f4f6; - --gray-scale-50: #f9fafb; - - --default-primary: #3692ff; - --default-error: #f74747; - - --banner-bg: #cfe5ff; - - --btn-color-hover: #1967d6; - --btn-color-active: #1251aa; - --btn-color-inactive: #9ca3af; -} - -/* 컴포넌트 */ - -.btn--large { - display: flex; - align-items: center; - justify-content: center; - width: 355px; - height: 56px; - border: none; - border-radius: 40px; - background-color: var(--default-primary); - text-decoration: none; - font-size: 24px; - color: #ffffff; -} - -.btn--small { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - - width: 128px; - height: 48px; - - text-decoration: none; - font-weight: 600; - color: #ffffff; - - border-radius: 8px; - background: var(--default-primary); -} diff --git a/sprint/index.css b/sprint/index.css deleted file mode 100644 index 7908c0967..000000000 --- a/sprint/index.css +++ /dev/null @@ -1,187 +0,0 @@ -* { - margin: 0; - padding: 0; -} - -html { - font-family: 'Pretendard'; - font-size: 8px; - user-select: none; -} - -body { - font-size: 2rem; -} - -.wrap { - min-width: 100vw; - width: 100%; - height: 100%; -} - -.header-wrap { - min-width: 1560px; - width: 100%; - height: 610px; -} - -.header { - display: flex; - flex-direction: column; - align-items: center; -} - -.nav { - position: sticky; - top: 0; - display: flex; - justify-content: center; - width: 100%; - height: 70px; - background-color: #ffffff; -} - -.nav__ul { - display: flex; - justify-content: space-between; - align-items: center; - max-width: 1520px; - width: 100%; - height: 100%; - list-style-type: none; -} - -.banner__top { - display: flex; - justify-content: center; - align-items: center; - min-width: 1520px; - width: 100%; - height: 540px; - background-color: var(--banner-bg); -} - -.banner__top__left { - display: flex; - flex-direction: column; - row-gap: 3rem; - justify-self: flex-end; -} - -.banner__top__right { - align-self: flex-end; - width: 996px; - height: 447px; -} - -.main-wrap { - width: 100vw; -} - -.main { - display: flex; - flex-direction: column; - align-items: center; - min-width: 1520px; - margin-top: 17.25rem; - margin-bottom: 17.25rem; -} - -.main__items { - display: grid; - grid-template-columns: 1fr 1fr; - align-items: center; - column-gap: 64px; - width: 1200px; -} - -.main__items.reverse { - direction: rtl; -} - -.main__item:first-of-type { - width: 588px; - height: 444px; -} - -.main__item:last-of-type { - span { - display: flex; - flex-direction: column; - row-gap: 12px; - font-weight: 500; - font-size: 3rem; - small { - color: var(--default-primary); - font-weight: 700; - font-size: 2.2rem; - } - h2 { - padding-bottom: 12px; - font-weight: 700; - font-size: 5rem; - } - } -} - - -.footer-wrap { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - min-width: 1560px; - width: 100%; - height: 680px; - background-color: var(--banner-bg); -} - -.banner__bottom{ - display: flex; - justify-content: center; - align-items: center; - min-width: 1520px; - height: 540px; -} - -.footer { - min-width: 1520px; - width: 100%; - height: 160px; - background-color: var(--gray-scale-900); -} - -.footer__items { - display: flex; - justify-content: space-around; - width: 100%; - margin-top: 32px; - list-style-type: none; -} - -.footer__item { - &:first-of-type { - color: var(--gray-scale-400); - } - &:nth-of-type(2) { - display: flex; - column-gap: 30px; - & > a { - color: #ffffff; - text-decoration: none; - } - } - &:last-of-type { - display: flex; - column-gap: 12px; - } -} - -@media (hover: hover) { - .nv:hover { - scale: 1.1; - } - .btn:hover { - background: var(--btn-color-hover) - } -} \ No newline at end of file diff --git a/sprint/index.html b/sprint/index.html index 9fc0ce566..b1555b107 100644 --- a/sprint/index.html +++ b/sprint/index.html @@ -3,149 +3,11 @@ + 판다 마켓 - - - -
-
-
- - -
-
- -
-
-
-
- -
-
- - Hot item -

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

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

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

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

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

- 어떤 물건이든 판매하고 싶은 상품을
- 쉽게 등록하세요 -
-
-
-
-
- -
- +
+ - + \ No newline at end of file diff --git a/sprint/main.css b/sprint/main.css new file mode 100644 index 000000000..cb9595ef2 --- /dev/null +++ b/sprint/main.css @@ -0,0 +1,217 @@ +@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css") +all; + +:root { + --clr-gray-900: #111827; + --clr-gray-800: #1f2937; + --clr-gray-700: #374151; + --clr-gray-600: #4b5563; + --clr-gray-500: #6b7280; + --clr-gray-400: #9ca3af; + --clr-gray-200: #e5e7eb; + --clr-gray-100: #f3f4f6; + --clr-gray-50: #f9fafb; + + --clr-primary: #3692ff; + --clr-error: #f74747; + --clr-banner: #cfe5ff; + --clr-hover-button: #1967d6; + --clr-active-button: #1251aa; + --clr-inactive-button: var(--clr-gray-400); + + --ff-body: "Pretendard"; + --fs-xxs: 8px; + --fs-xs: 10px; + --fs-s: 12px; + --fs-ms: 14px; + --fs-m: 16px; + --fs-ml: 18px; + --fs-l: 20px; + --fs-xl: 24px; + --fs-xxl: 40px; + + --fw-500: 500; + --fw-700: 700; + + --height-header: 70px; + + --width-large-button: 355px; + --width-small-button: 128px; + --height-large-button: 56px; + --height-small-button: 48px; + + --width-banner: 996px; + --height-banner: 447px; + + --z-header: 100; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +body, +h1, +h2, +h3, +h4, +h5, +h6, +blockquote, +dl, +dd { + margin: 0; +} + +ul[role="list"], +ol[role="list"] { + list-style: none; +} + +html:focus-within { + scroll-behavior: smooth; +} + +body { + text-rendering: optimizeSpeed; + line-height: 1.5; + font-family: var(--ff-body); + font-size: var(--fs-m); +} + +a:not([class]) { + text-decoration-skip-ink: auto; +} + +a { + cursor: pointer; +} + +img, +picture { + display: block; + max-width: 100%; +} + +input, +button, +select, +textarea { + font: inherit; +} + +@media (prefers-reduced-motion: reduce) { + html:focus-within { + scroll-behavior: auto; + } + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} + +.btn { + display: inline-block; + border: none; + width: 100%; + height: 100%; + text-decoration: none; + text-align: center; + cursor: pointer; +} + +.btn-small { + max-width: var(--width-small-button); + max-height: var(--height-small-button); + border-radius: var(--fs-xxs); + line-height: var(--height-small-button); +} + +.btn-large { + max-width: var(--width-large-button); + min-height: var(--height-large-button); + border-radius: var(--fs-xxl); + line-height: var(--height-large-button); + font-size: var(--fs-l); +} + +.btn-submit { + border-radius: var(--fs-xxl); + height: 56px; +} + +.btn-primary { + color: white; + background: var(--clr-primary); +} + +.btn-inactive { + color: white; + background: var(--clr-inactive-button); + user-select: none; + cursor: default; +} + +.wrap { + --height: 100%; + width: min(var(--max-width) - var(--padding) * 2, 100%); + height: var(--height); + margin-inline: auto; +} + +.h1 { + font-size: var(--fs-xxl); + font-weight: var(--fw-700); +} + +.h2 { + font-size: var(--fs-m); + font-weight: 500; +} + +.small { + font-size: var(--fs-ml); + font-weight: var(--fw-700); +} + +.small-primary { + color: var(--clr-primary); +} + +.p { + font-size: var(--fs-l); + font-weight: var(--fw-500); +} + +a[role="link"] { + text-decoration: none; +} + +.form-item { + display: flex; + flex-direction: column; +} + +.form-label { + font-weight: 700; + font-size: var(--fs-ml); +} + +.form-input { + height: 56px; + padding: var(--fs-m) var(--fs-xl); + background: var(--clr-gray-100); + border: none; + border-radius: 12px; +} + +.form-label.success { + color: green; +} diff --git a/sprint/main.js b/sprint/main.js new file mode 100644 index 000000000..69a5b71a5 --- /dev/null +++ b/sprint/main.js @@ -0,0 +1,28 @@ +"use strict"; + +import CustomRouter from "./src/utils/CustomRouter.js"; +import CustomElement from "./src/utils/CustomElement.js"; +import Root from "./src/Root.js"; +import Home from "./src/pages/Home.js"; +import In from "./src/pages/sign/in.js"; +import Up from "./src/pages/sign/Up.js"; + +document.addEventListener("DOMContentLoaded", () => { + CustomRouter.createRouteElements([ + { + path: "home", + component: Home, + default: true, + }, + { + path: "sign-in", + component: In, + }, + { + path: "sign-up", + component: Up, + }, + ]); + + CustomElement().define(document.getElementById("root"), Root); +}); diff --git a/sprint/src/Login.css b/sprint/src/Login.css deleted file mode 100644 index 2318235f6..000000000 --- a/sprint/src/Login.css +++ /dev/null @@ -1,117 +0,0 @@ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -html { - font-size: 8px; -} - -body { - min-width: 100vw; - min-height: 100vh; - width: 100%; - height: 100%; - font-size: 2rem; -} - -.wrap { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.form__logo { - width: 396px; - height: 132px; - margin-top: 60px; -} - -.form__ul { - display: grid; - grid-template-columns: 640px; - grid-template-rows: 93px 93px 56px 74px 18px; - row-gap: 24px; - list-style-type: none; -} - -.form__li { - position: relative; - display: flex; - flex-direction: column; - row-gap: 16px; -} - -.form__li:last-of-type { - justify-self: center; -} - -.form__label { - display: block; - font-size: 2.25rem; - font-weight: 700; -} - -.form__input { - width: 100%; - height: 100%; - padding: 16px 24px; - border: none; - border-radius: 12px; - background-color: var(--gray-scale-100); -} - -.form__input__wrap { - position: relative; -} - -.form__input::placeholder { - text-align: left; -} - -.form__input:focus { - border: 1px solid var(--default-primary); -} - -.password__logo { - background-image: url("../assets/icon_visibility_off.svg"); - background-repeat: no-repeat; - background-position: center; - position: absolute; - top: 0; - right: 20px; - width: 24px; - height: 100%; - cursor: pointer; -} - -.form__submit { - display: block; - width: 100%; - height: 100%; - border: none; - border-radius: 5rem; - font-size: 2.5rem; - font-weight: 600; - color: #ffffff; - background: var(--gray-scale-400); - cursor: pointer; -} - -.form__social { - display: flex; - align-items: center; - justify-content: space-between; - background-color: var(--banner-bg); - height: 100%; - padding: 2.9rem; - font-size: 16px; - font-weight: 500; - - span:nth-of-type(2) { - display: flex; - column-gap: 2rem; - } -} diff --git a/sprint/src/Login.html b/sprint/src/Login.html deleted file mode 100644 index 952195cb2..000000000 --- a/sprint/src/Login.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - 판다 마켓 - 로그인 페이지 - - -
- - - - -
- - diff --git a/sprint/src/Root.js b/sprint/src/Root.js new file mode 100644 index 000000000..efe3ac80c --- /dev/null +++ b/sprint/src/Root.js @@ -0,0 +1,13 @@ +"use strict"; + +import CustomRouter from "./utils/CustomRouter.js"; + +export default function () { + function template(root) { + return CustomRouter.routing(root); + } + + function event() {} + function css() {} + return { template, event, css }; +} diff --git a/sprint/src/constant/Event.js b/sprint/src/constant/Event.js new file mode 100644 index 000000000..7c45f8717 --- /dev/null +++ b/sprint/src/constant/Event.js @@ -0,0 +1,109 @@ +"use strict"; + +import CustomRouter from "../utils/CustomRouter.js"; +import ID from "./ID.js"; +import Regex from "./Regex.js"; +import Message from "./Message.js"; + +function navigateTo(to, root) { + CustomRouter.setRoute(to, root); + if (to === "home") { + window.location.reload(); + window.scrollTo(0, 0); + } +} + +function submitToggle(form, isCompleted) { + const button = form.querySelector(".btn-submit"); + button.classList.toggle("btn-primary", isCompleted); + button.classList.toggle("btn-inactive", !isCompleted); +} + +function formCheck(target, root) { + const section = target.closest("section"); + const desc = section.querySelector(".form-desc"); + let { name, value } = target; + desc.textContent = ""; + + if (!value) { + target.classList.toggle("error", true); + desc.textContent = Message[name]["empty"]; + return; + } + target.classList.toggle("error", false); + + const form = target.closest("form"); + const formData = new FormData(form); + + let isValid; + if (name !== "_password") { + isValid = Regex[name].test(value); + } else { + const password = formData.get("password"); + isValid = password === value; + } + + if (!isValid) { + desc.textContent = Message[name]["invalid"]; + target.classList.add("error"); + target.value = ""; + submitToggle(form, false); + return; + } + + let isCompleted = formData.entries().every((entry) => entry[1]); + submitToggle(form, isCompleted); +} + +function passwordVisibility(target) { + const pwInput = target.previousElementSibling; + const visible = target.dataset.visible === "true"; + pwInput.setAttribute("type", visible ? "text" : "password"); + target.src = visible + ? "./assets/svg/ic_visibility_on.svg" + : "./assets/svg/ic_visibility_off.svg"; + target.dataset.visible = String(!visible); +} + +export default { + [ID.HOME_CONTAINER]: { + click: ({ target }, root) => { + const dataset = target.dataset; + if (dataset.hasOwnProperty("to")) { + navigateTo(dataset.to, root); + } else if (dataset.hasOwnProperty("visible")) { + passwordVisibility(target); + } + }, + }, + [ID.SIGN_IN_CONTAINER]: { + click: ({ target }, root) => { + const dataset = target.dataset; + if (dataset.hasOwnProperty("to")) { + navigateTo(dataset.to, root); + } else if (dataset.hasOwnProperty("visible")) { + passwordVisibility(target); + } + }, + focusout: ({ target }) => { + if (target.classList.contains("form-input")) { + formCheck(target, root); + } + }, + }, + [ID.SIGN_UP_CONTAINER]: { + click: ({ target }, root) => { + const dataset = target.dataset; + if (dataset.hasOwnProperty("to")) { + navigateTo(dataset.to, root); + } else if (dataset.hasOwnProperty("visible")) { + passwordVisibility(target); + } + }, + focusout: ({ target }) => { + if (target.classList.contains("form-input")) { + formCheck(target, root); + } + }, + }, +}; diff --git a/sprint/src/constant/ID.js b/sprint/src/constant/ID.js new file mode 100644 index 000000000..11be1aa45 --- /dev/null +++ b/sprint/src/constant/ID.js @@ -0,0 +1,11 @@ +"use strict"; + +const HOME_CONTAINER = "#home-container"; +const SIGN_IN_CONTAINER = "#sign-in-container"; +const SIGN_UP_CONTAINER = "#sign-up-container"; + +export default { + HOME_CONTAINER, + SIGN_IN_CONTAINER, + SIGN_UP_CONTAINER, +}; diff --git a/sprint/src/constant/Message.js b/sprint/src/constant/Message.js new file mode 100644 index 000000000..578f5228e --- /dev/null +++ b/sprint/src/constant/Message.js @@ -0,0 +1,18 @@ +export default { + email: { + empty: "이메일을 입력해주세요.", + invalid: "잘못된 이메일 형식입니다.", + }, + nickname: { + empty: "닉네임을 입력해주세요.", + invalid: "닉네임은 2 ~ 64자리 사이입니다.", + }, + password: { + empty: "비밀번호를 입력해주세요.", + invalid: "비밀번호는 8자리 이상입니다.", + }, + _password: { + empty: "비밀번호를 입력해주세요.", + invalid: "일치하지 않는 비밀번호입니다.", + }, +}; diff --git a/sprint/src/constant/Regex.js b/sprint/src/constant/Regex.js new file mode 100644 index 000000000..afe8c7554 --- /dev/null +++ b/sprint/src/constant/Regex.js @@ -0,0 +1,5 @@ +export default { + email: /^(?!=\d)[\w.-]+@[a-zA-Z\d.-]+\.[a-zA-Z]{2,}$/, + password: /^.{8,}$/, + nickname: /^.{2,64}$/, +}; diff --git a/sprint/src/pages/Home.css b/sprint/src/pages/Home.css new file mode 100644 index 000000000..77297f68a --- /dev/null +++ b/sprint/src/pages/Home.css @@ -0,0 +1,289 @@ +.container { + display: grid; + grid-template: + "header" var(--height-header) + "main" auto + "footer" 160px + / auto; +} + +.header { + grid-area: header; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: var(--height-header); + background: white; + z-index: var(--z-header); + + .wrap { + --max-width: 1920px; + --padding: 200px; + display: flex; + justify-content: space-between; + align-items: center; + padding-left: 1rem; + padding-right: 1rem; + } +} + +.main { + grid-area: main; +} + +.banner-top { + background: var(--clr-banner); + + .wrap { + position: relative; + } + + .img { + object-fit: cover; + } +} + +@media screen and (min-width: 769px) { + .banner-top { + .wrap { + --max-width: 1920px; + --padding: 200px; + --height: var(--height-banner); + } + + .left { + position: absolute; + top: 50%; + left: 10%; + transform: translateY(-50%); + width: calc(var(--width-large-button) + 2rem); + z-index: 2; + } + + .right { + position: absolute; + right: 0; + bottom: 0; + z-index: 1; + } + } +} + +@media screen and (max-width: 768px) { + .banner-top { + .wrap { + --max-width: 768px; + --padding: 0px; + --height: calc(100vh - var(--height-header)); + } + + .left { + position: absolute; + transform: translateX(-50%); + top: 1rem; + left: 50%; + width: 100%; + padding-left: 1rem; + padding-right: 1rem; + text-align: center; + + .h1 { + margin-bottom: 1rem; + } + } + + .right { + position: absolute; + bottom: 0; + } + } +} + +.content { + .wrap { + padding-left: 1rem; + padding-right: 1rem; + } +} + +.content.reverse { + .wrap { + direction: rtl; + } +} + +@media screen and (min-width: 769px) { + .content { + margin: 138px 0; + + .wrap { + --max-width: 1200px; + --padding: 0px; + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 444px; + column-gap: 64px; + } + + .left { + justify-self: flex-end; + align-self: center; + } + + .img { + object-fit: contain; + } + } +} + +@media screen and (max-width: 768px) { + .content { + min-height: calc(100vh - var(--height-header)); + margin: 64px 0; + .wrap { + --max-width: 768px; + --padding: 0px; + display: grid; + grid-template-rows: fit-content fit-content; + justify-content: center; + align-items: center; + row-gap: 32px; + } + + .img { + object-fit: cover; + } + } +} + +.banner-bottom { + background: var(--clr-banner); + + .wrap { + position: relative; + } + + .wrap > :nth-child(1) { + position: absolute; + z-index: 2; + } + + .wrap > :nth-child(2) { + position: absolute; + z-index: 1; + } + + .img { + object-fit: cover; + } +} + +@media screen and (min-width: 769px) { + .banner-bottom { + .wrap { + --max-width: 1520px; + --padding: 0px; + --height: 540px; + } + + .wrap > :nth-child(1) { + top: 50%; + transform: translateY(-50%); + padding-left: 1rem; + } + + .wrap > :nth-child(2) { + top: 50%; + right: 0; + transform: translateY(-50%); + } + } +} + +@media screen and (max-width: 768px) { + .banner-bottom { + .wrap { + --max-width: 768px; + --padding: 0rem; + --height: calc(100vh - var(--height-header)); + } + .wrap > :nth-child(1) { + top: 5%; + width: 100%; + text-align: center; + } + + .wrap > :nth-child(2) { + left: 50%; + bottom: 0; + transform: translateX(-50%); + } + } +} + +.footer { + grid-area: footer; + background: var(--clr-gray-900); + + .origin { + color: var(--clr-gray-400); + } + + .wrap > :nth-child(2) { + a { + color: white; + } + } +} + +@media screen and (min-width: 769px) { + .footer { + .wrap { + --max-width: 1520px; + --padding: 200px; + --height: auto; + display: flex; + justify-content: space-around; + margin-top: 32px; + } + + .wrap > :nth-child(2) { + display: flex; + column-gap: 32px; + } + + .wrap > :nth-child(3) { + display: flex; + column-gap: var(--fs-xxs); + } + } +} + +@media screen and (max-width: 768px) { + .footer { + .wrap { + --max-width: 768px; + --padding: 0px; + display: grid; + grid-auto-flow: row; + grid-auto-rows: auto; + justify-items: center; + align-items: center; + } + + .wrap > :nth-child(2) { + display: flex; + column-gap: var(--fs-xxl); + } + + .wrap > :nth-child(3) { + display: flex; + column-gap: var(--fs-xxl); + img { + width: 32px; + height: 32px; + } + } + } +} diff --git a/sprint/src/pages/Home.js b/sprint/src/pages/Home.js new file mode 100644 index 000000000..4ce11526b --- /dev/null +++ b/sprint/src/pages/Home.js @@ -0,0 +1,149 @@ +"use strict"; + +import Event from "../constant/Event.js"; +import ID from "../constant/ID.js"; + +export default function () { + async function css(root) { + const response = await fetch(`./src/pages/Home.css`); + const css = await response.text(); + const style = root.querySelector("style"); + style.textContent = css; + } + + function event(root) { + const container = root.querySelector(ID.HOME_CONTAINER); + Object.entries(Event[ID.HOME_CONTAINER]).forEach(([type, action]) => { + container.addEventListener(type, (e) => action(e, container)); + }); + } + + function template(root) { + root.innerHTML = ` + +
+
+ +
+
+ +
+
+
+ Hot Item +

인기 상품을
확인해 보세요

+

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

+
+
+ +
+
+
+
+
+
+ Search +

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

+

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

+
+
+ +
+
+
+
+
+
+ Register +

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

+

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

+
+
+ +
+
+
+ +
+ +
+ `; + } + + return { event, css, template }; +} diff --git a/sprint/src/pages/sign/In.css b/sprint/src/pages/sign/In.css new file mode 100644 index 000000000..d0c695880 --- /dev/null +++ b/sprint/src/pages/sign/In.css @@ -0,0 +1,73 @@ +.container { + display: grid; + grid-template: + "header" 192px + "main" auto + / 100%; + justify-content: center; +} + +.header { + grid-area: header; + .wrap { + --max-width: 1920px; + --padding: 762px; + display: flex; + justify-content: center; + align-items: flex-end; + padding: 1rem; + } +} + +.main { + grid-area: main; + .wrap { + --max-width: 1920px; + --padding: 640px; + display: flex; + flex-direction: column; + row-gap: var(--fs-xl); + padding: 0 1rem; + } + + .form-input.error::placeholder { + color: red; + } + + .form-item:nth-of-type(1), + .form-item:nth-of-type(2) { + row-gap: 1rem; + } + + .form-item:nth-of-type(2) { + position: relative; + } + + .password-icon { + position: absolute; + cursor: pointer; + top: 61px; + right: 1rem; + } + + .form-item:nth-of-type(4) { + flex-direction: row; + justify-content: space-between; + background: var(--clr-banner); + align-items: center; + height: 74px; + padding: 0 23px; + } + + .form-item:nth-of-type(5) { + text-align: center; + a { + color: var(--clr-primary); + } + } + + .site { + display: flex; + column-gap: 16px; + } +} diff --git a/sprint/src/pages/sign/In.js b/sprint/src/pages/sign/In.js new file mode 100644 index 000000000..aec3059e6 --- /dev/null +++ b/sprint/src/pages/sign/In.js @@ -0,0 +1,99 @@ +"use strict"; + +import Event from "../../constant/Event.js"; +import ID from "../../constant/ID.js"; + +export default function () { + async function css(root) { + const response = await fetch(`./src/pages/sign/In.css`); + const css = await response.text(); + const style = root.querySelector("style"); + style.textContent = css; + } + + function event(root) { + const container = root.querySelector(ID.SIGN_IN_CONTAINER); + Object.entries(Event[ID.SIGN_IN_CONTAINER]).forEach(([type, action]) => { + container.addEventListener(type, (e) => action(e, container)); + }); + } + + function template(root) { + root.innerHTML = ` + +
+
+
+ + + +
+
+
+
+
+ + + +
+
+ + + + +
+
+ +
+
+

간편 로그인하기

+ +
+
+

+ 판다마켓이 처음이신가요? + 회원가입 +

+
+
+
+
+ `; + } + + return { css, event, template }; +} diff --git a/sprint/src/pages/sign/Up.css b/sprint/src/pages/sign/Up.css new file mode 100644 index 000000000..799f41c8a --- /dev/null +++ b/sprint/src/pages/sign/Up.css @@ -0,0 +1,76 @@ +.container { + display: grid; + grid-template: + "header" 192px + "main" auto + / 100%; + justify-content: center; +} + +.header { + grid-area: header; + .wrap { + --max-width: 1920px; + --padding: 762px; + display: flex; + justify-content: center; + align-items: flex-end; + padding: 1rem; + } +} + +.main { + grid-area: main; + .wrap { + --max-width: 1920px; + --padding: 640px; + display: flex; + flex-direction: column; + row-gap: var(--fs-xl); + padding: 0 1rem; + } + + .form-input.error { + border: 2px solid red; + } + + .form-item:nth-of-type(1), + .form-item:nth-of-type(2), + .form-item:nth-of-type(3), + .form-item:nth-of-type(4) { + row-gap: 1rem; + } + + .form-item:nth-of-type(3), + .form-item:nth-of-type(4) { + position: relative; + } + + .password-icon { + position: absolute; + cursor: pointer; + top: 61px; + right: 1rem; + } + + .form-item:nth-of-type(6) { + flex-direction: row; + justify-content: space-between; + background: var(--clr-banner); + align-items: center; + height: 74px; + padding: 0 23px; + } + + .form-item:nth-of-type(7) { + text-align: center; + a { + color: var(--clr-primary); + } + } + + .site { + display: flex; + column-gap: 16px; + } +} diff --git a/sprint/src/pages/sign/Up.js b/sprint/src/pages/sign/Up.js new file mode 100644 index 000000000..1d6d84c7f --- /dev/null +++ b/sprint/src/pages/sign/Up.js @@ -0,0 +1,129 @@ +"use strict"; + +import Event from "../../constant/Event.js"; +import ID from "../../constant/ID.js"; + +export default function () { + async function css(root) { + const response = await fetch(`./src/pages/sign/Up.css`); + const css = await response.text(); + const style = root.querySelector("style"); + style.textContent = css; + } + + function event(root) { + const container = root.querySelector(ID.SIGN_UP_CONTAINER); + Object.entries(Event[ID.SIGN_UP_CONTAINER]).forEach(([type, action]) => { + container.addEventListener(type, (e) => action(e, container)); + }); + } + + function template(root) { + root.innerHTML = ` + +
+
+
+ + + +
+
+
+
+
+ + + +
+
+ + + +
+
+ + + + +
+
+ + + + +
+
+ +
+
+

간편 로그인하기

+ +
+
+

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

+
+
+
+
+ `; + } + + return { css, event, template }; +} diff --git a/sprint/src/utils/CustomElement.js b/sprint/src/utils/CustomElement.js new file mode 100644 index 000000000..b55172613 --- /dev/null +++ b/sprint/src/utils/CustomElement.js @@ -0,0 +1,22 @@ +"use strict"; + +export default function () { + let root; + let component; + + function define(initRoot, initComponent) { + root = initRoot; + component = initComponent; + connected(); + } + + function connected() { + const { css, template, event } = component(); + + css(root); + template(root); + event(root); + } + + return { define }; +} diff --git a/sprint/src/utils/CustomRouter.js b/sprint/src/utils/CustomRouter.js new file mode 100644 index 000000000..76210963e --- /dev/null +++ b/sprint/src/utils/CustomRouter.js @@ -0,0 +1,30 @@ +"use strict"; + +import CustomElement from "./CustomElement.js"; + +export default (function () { + let routes; + let route; + + function createRouteElements(initRoutes) { + routes = initRoutes; + route = routes.find((route) => route.default); + } + + function currentRoute() { + return route; + } + + function setRoute(newPath, root) { + route = routes.find((route) => route.path === newPath); + routing(root); + } + + function routing(root) { + root.innerHTML = ""; + root.innerHTML = "
"; + CustomElement().define(document.getElementById("router"), route.component); + } + + return { createRouteElements, currentRoute, setRoute, routing }; +})();