diff --git a/week4/css/reset.css b/week4/css/reset.css
new file mode 100644
index 000000000..e193e1f79
--- /dev/null
+++ b/week4/css/reset.css
@@ -0,0 +1,15 @@
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+input {
+ outline: none;
+ background: none;
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
\ No newline at end of file
diff --git a/week4/css/style.css b/week4/css/style.css
new file mode 100644
index 000000000..3721dd739
--- /dev/null
+++ b/week4/css/style.css
@@ -0,0 +1,183 @@
+@charset "utf-8";
+
+:root {
+ --main-bg-color: #f0f6ff;
+ --primary-color: #6d6afe;
+ --box-border-color: #ccd5e3;
+ --white-color: #fff;
+ --black-color: #373740;
+ --btn-color: #f5f5f5;
+ --sns-bg-color: #e7effb;
+}
+
+body {
+ font-family: 'Pretendard';
+ background-color: var(--main-bg-color);
+}
+
+.container {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ width: 100%;
+}
+
+.inner-wrap {
+ max-width: 400px;
+ margin: 0 auto;
+}
+
+.join-member .logo {
+ text-align: center;
+}
+
+.join-member .logo img {
+ width: 210px;
+}
+
+.join-member .logo span {
+ overflow: hidden;
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ clip-path: rect(0 0 0 0);
+}
+
+.join-link {
+ display: flex;
+ justify-content: center;
+ gap: 8px;
+ margin: 16px 0 0;
+}
+
+.join-link .btn-join {
+ color: var(--primary-color);
+ font-weight: 600;
+ line-height: 19px;
+ border-bottom: 1px solid var(--primary-color);
+}
+
+.form-wrap {
+ margin: 30px 0 0;
+}
+
+.form-wrap label {
+ display: block;
+ margin: 0 0 12px 0;
+ font-size: 14px;
+ line-height: 16px;
+}
+
+.form-wrap input {
+ width: 100%;
+ padding: 18px 15px;
+ color: var(--black-color);
+ border-radius: 8px;
+ border: 1px solid var(--box-border-color);
+ background-color: var(--white-color);
+}
+
+.form-wrap input:focus {
+ border: 1px solid var(--primary-color);
+}
+
+.form-box.active input {
+ border: 1px solid #ff5b56;
+}
+
+.form-box.active .messeage {
+ display: block;
+ margin: 6px 0 0;
+ color: #ff5b56;
+ font-size: 14px;
+ line-height: 16px;
+}
+
+.form-box + .form-box {
+ margin: 24px 0 0;
+}
+
+.form-box .user-password {
+ position: relative;
+}
+
+.form-box .user-password img[class*="eye"] {
+ position: absolute;
+ top: 50%;
+ right: 15px;
+ transform: translateY(-50%);
+ cursor: pointer;
+}
+
+.btn-box {
+ margin: 30px 0 0;
+}
+
+.btn-box button {
+ display: block;
+ width: 100%;
+ padding: 16px 20px;
+ border: 0;
+ border-radius: 8px;
+ text-align: center;
+ font-size: 18px;
+ font-weight: 600;
+ line-height: 21px;
+ cursor: pointer;
+ color: var(--btn-color);
+ background: linear-gradient(90.99deg, #6D6AFE 0.12%, #6AE3FE 101.84%);
+}
+
+.sns-login {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 32px 0 0;
+ padding: 12px 24px;
+ border-radius: 8px;
+ font-size: 14px;
+ line-height: 16px;
+ border: 1px solid var(--box-border-color);
+ background-color: var(--sns-bg-color);
+}
+
+.sns-login .title {
+ font-size: 14px;
+ line-height: 16px;
+ color: var(--black-color);
+}
+
+.sns-login ul {
+ overflow: hidden;
+ list-style-type: none;
+}
+
+.sns-login ul li {
+ float: left;
+ margin: 0 16px 0 0;
+}
+
+.sns-login ul li:last-child {
+ margin: 0;
+}
+
+.sns-login ul li a {
+ display: block;
+ overflow: hidden;
+ width: 42px;
+ height: 42px;
+ text-indent: 100%;
+ white-space: nowrap;
+}
+
+.sns-login ul li .google {
+ background: url('../images/ico-google.png') no-repeat;
+ background-size: 100% 42px;
+}
+
+.sns-login ul li .kakao {
+ background: url('../images/ico-kakao.png') no-repeat;
+ background-size: 100% 42px;
+}
\ No newline at end of file
diff --git a/week4/folder.html b/week4/folder.html
new file mode 100644
index 000000000..0cc50450c
--- /dev/null
+++ b/week4/folder.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+ folder
+
+
\ No newline at end of file
diff --git a/week4/images/ico-eye-off.svg b/week4/images/ico-eye-off.svg
new file mode 100644
index 000000000..783dc1b11
--- /dev/null
+++ b/week4/images/ico-eye-off.svg
@@ -0,0 +1,3 @@
+
diff --git a/week4/images/ico-eye-on.svg b/week4/images/ico-eye-on.svg
new file mode 100644
index 000000000..61350f131
--- /dev/null
+++ b/week4/images/ico-eye-on.svg
@@ -0,0 +1,4 @@
+
diff --git a/week4/images/ico-google.png b/week4/images/ico-google.png
new file mode 100644
index 000000000..b7b03aa92
Binary files /dev/null and b/week4/images/ico-google.png differ
diff --git a/week4/images/ico-kakao.png b/week4/images/ico-kakao.png
new file mode 100644
index 000000000..02a97d571
Binary files /dev/null and b/week4/images/ico-kakao.png differ
diff --git a/week4/images/logo.svg b/week4/images/logo.svg
new file mode 100644
index 000000000..f3beb240f
--- /dev/null
+++ b/week4/images/logo.svg
@@ -0,0 +1,11 @@
+
diff --git a/week4/js/signin.js b/week4/js/signin.js
new file mode 100644
index 000000000..0886818f3
--- /dev/null
+++ b/week4/js/signin.js
@@ -0,0 +1,92 @@
+const form = document.querySelector('form');
+const formBox = document.querySelectorAll('.form-box');
+const emailPattern = /^[A-Za-z0-9.\-_]+@([A-Za-z0-9-]+\.)+[A-Za-z]{2,6}$/;
+const pwPattern = /^(?=.*[a-zA-Z])(?=.*[0-9]).{8,25}$/;
+const userEmail = 'test@codeit.com';
+const emailInput = document.getElementById('signin-email');
+const pwInput = document.getElementById('signin-password');
+const userPw = 'codeit101';
+const btnLogin = document.querySelector('.btn-box .btn-login');
+const eyeOff = document.querySelector('.eye-off');
+
+// 이메일, 비밀번호 유효성 검사
+formBox.forEach((el) => {
+ el.addEventListener('focusout', (e)=> {
+ if(e.target.value === ''){
+ e.currentTarget.classList.add('active');
+
+ el.classList.contains('email') ? e.currentTarget.lastElementChild.textContent = '이메일을 입력하세요' : e.currentTarget.lastElementChild.textContent = '비밀번호를 입력하세요';
+ }else{
+ e.currentTarget.classList.remove('active');
+ e.currentTarget.lastElementChild.textContent = '';
+ validate(emailPattern, pwPattern);
+ }
+
+ function validate(emailPattern, pwPattern){
+ if(el.classList.contains('email')){
+ if(emailPattern.test(e.target.value) === false){
+ e.currentTarget.classList.add('active');
+ e.currentTarget.lastElementChild.textContent = '올바른 이메일 주소가 아닙니다.';
+ }
+ }else{
+ if(pwPattern.test(e.target.value) === false){
+ e.currentTarget.classList.add('active');
+ e.currentTarget.lastElementChild.textContent = '비밀번호는 영문, 숫자 조합 8자 이상 입력해 주세요.';
+ }
+ }
+ }
+ });
+});
+
+// 로그인 버튼 클릭 시 이메일, 비밀번호 일치여부 확인 후 페이지 이동
+function login(e){
+ e.preventDefault();
+
+ formBox.forEach((el) => {
+ if(!el.classList.contains('active')){
+ if(emailInput.value === userEmail && pwInput.value === userPw){
+ form.submit();
+ }else{
+ formBox.forEach((el) => {
+ el.classList.add('active');
+ el.classList.contains('email') ? el.lastElementChild.textContent = '이메일을 확인해주세요.' : el.lastElementChild.textContent = '비밀번호를 확인해주세요.';
+ })
+ }
+ }
+ })
+}
+btnLogin.addEventListener('click', login);
+
+form.addEventListener('keydown', (e) => {
+ if(e.key === 'Enter'){
+ e.preventDefault();
+ }
+})
+
+// 눈 아이콘 클릭 시 비밀번호 안보이게 하기
+function eyeOn(e){
+ e.preventDefault();
+
+ e.target.parentElement.classList.toggle('active');
+ if(e.target.parentElement.classList.contains('active')){
+ e.target.previousElementSibling.setAttribute('type', 'text');
+ e.target.setAttribute('src', './images/ico-eye-on.svg');
+ }else{
+ e.target.previousElementSibling.setAttribute('type', 'password');
+ e.target.setAttribute('src', './images/ico-eye-off.svg');
+ }
+}
+eyeOff.addEventListener('click', eyeOn);
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week4/js/signup.js b/week4/js/signup.js
new file mode 100644
index 000000000..8ec218d38
--- /dev/null
+++ b/week4/js/signup.js
@@ -0,0 +1,104 @@
+const form = document.querySelector('form');
+const formBox = document.querySelectorAll('.form-box');
+const emailPattern = /^[A-Za-z0-9.\-_]+@([A-Za-z0-9-]+\.)+[A-Za-z]{2,6}$/;
+const pwPattern = /^(?=.*[a-zA-Z])(?=.*[0-9]).{8,25}$/;
+const userEmail = 'test@codeit.com';
+const emailInput = document.getElementById('signin-email');
+const pwInput = document.getElementById('signin-password');
+const userPw = 'codeit101';
+const emailInputUp = document.getElementById('signup-email');
+const pwInputUp = document.getElementById('signup-password');
+const userPwCheck = document.getElementById('signup-check-password');
+const btnJoin = document.querySelector('.btn-box .btn-join');
+const eyeOn = document.querySelectorAll('.eye-on');
+
+// 이메일, 비밀번호 유효성 검사
+formBox.forEach((el) => {
+ el.addEventListener('focusout', (e)=> {
+ if(e.target.value === ''){
+ e.currentTarget.classList.add('active');
+
+ el.classList.contains('email') ? e.currentTarget.lastElementChild.textContent = '이메일을 입력하세요' : e.currentTarget.lastElementChild.textContent = '비밀번호를 입력하세요';
+ }else{
+ if(el.classList.contains('pw')){
+ e.currentTarget.classList.remove('active');
+ e.currentTarget.lastElementChild.textContent = '';
+
+ validate(emailPattern, pwPattern);
+ }
+
+ function validate(emailPattern, pwPattern){
+ if(el.classList.contains('email')){
+ if(emailPattern.test(e.target.value) === false){
+ e.currentTarget.classList.add('active');
+ e.currentTarget.lastElementChild.textContent = '올바른 이메일 주소가 아닙니다.';
+ }
+ }else{
+ if(pwPattern.test(e.target.value) === false){
+ e.currentTarget.classList.add('active');
+ e.currentTarget.lastElementChild.textContent = '비밀번호는 영문, 숫자 조합 8자 이상 입력해 주세요.';
+ }
+ }
+ }
+ }
+ });
+});
+
+// 회원가입 버튼 클릭 시 가입된 이메일 존재 여부 확인 후 페이지 이동
+function join(e){
+ e.preventDefault();
+
+ formBox.forEach((el) => {
+ if(!el.classList.contains('active')){
+ if(emailInputUp.value === userEmail){
+ if(el.classList.contains('email')){
+ el.classList.add('active');
+ el.lastElementChild.textContent = '이미 사용 중인 이메일입니다.';
+ }else{
+ el.classList.remove('active');
+ el.lastElementChild.textContent = '';
+ }
+ }else{
+ form.submit();
+ }
+ }
+ })
+}
+btnJoin.addEventListener('click', join);
+
+// 비밀번호 input과 비밀번호 확인 input의 값이 다른 경우
+function pwCheck(e){
+ if(pwInputUp.value !== userPwCheck.value){
+ e.target.parentElement.parentElement.classList.add('active');
+ e.target.parentElement.parentElement.lastElementChild.textContent = '비밀번호가 일치하지 않아요.';
+ }
+}
+userPwCheck.addEventListener('focusout', pwCheck);
+
+// 눈 아이콘 클릭 시 비밀번호 보이게 하기
+function eyeOff(e){
+ e.preventDefault();
+
+ e.target.parentElement.classList.toggle('active');
+ if(e.target.parentElement.classList.contains('active')){
+ e.target.previousElementSibling.setAttribute('type', 'password');
+ e.target.setAttribute('src', './images/ico-eye-off.svg');
+ }else{
+ e.target.previousElementSibling.setAttribute('type', 'text');
+ e.target.setAttribute('src', './images/ico-eye-on.svg');
+ }
+}
+eyeOn.forEach((eye) => {eye.addEventListener('click', eyeOff)})
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week4/signin.html b/week4/signin.html
new file mode 100644
index 000000000..dbd7af9f7
--- /dev/null
+++ b/week4/signin.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+ 로그인
+
+
+
+
+
+
+
+
+
diff --git a/week4/signup.html b/week4/signup.html
new file mode 100644
index 000000000..b8cac9668
--- /dev/null
+++ b/week4/signup.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+ 회원가입
+
+
+
+
+
+
+
+
+