diff --git a/Mission-FE-Zero100 b/Mission-FE-Zero100
new file mode 160000
index 0000000..839460c
--- /dev/null
+++ b/Mission-FE-Zero100
@@ -0,0 +1 @@
+Subproject commit 839460c80639bc697cb6f3621879e9e8900adf57
diff --git a/src/App.css b/src/App.css
index 66f8f1f..1d3d268 100644
--- a/src/App.css
+++ b/src/App.css
@@ -3,18 +3,23 @@ body {
font-family: Arial, sans-serif; /* 폰트 변경 */
display: flex;
justify-content: center;
- align-items: center;
+ align-items: flex-start; /* 상단 정렬 */
min-height: 100vh;
margin: 0;
background-color: #fff;
+ padding-top: 50px; /* 상단 여백 추가 */
}
.app-container {
max-width: 600px;
width: 100%;
padding: 20px;
+ /* 그림자에 대한 언급은 없으므로 제거하거나 유지 */
+ /* box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); */
+ background-color: #fff; /* 배경색 확실히 지정 */
}
+/* 기존 요소들 스타일 */
h1 {
font-size: 2.5rem;
font-weight: bold;
@@ -29,7 +34,7 @@ h2 {
text-align: left;
}
-/* 입력창 */
+/* 입력창 (AddTodo) */
.input-container {
margin-bottom: 10px;
}
@@ -40,7 +45,8 @@ h2 {
font-size: 1rem;
border: 2px solid #333; /* 입력창만 굵은 테두리 */
border-radius: 0;
- box-sizing: border-box;
+ box-sizing: border-box; /* 패딩과 테두리가 width에 포함되도록 */
+ outline: none; /* 포커스 시 기본 외곽선 제거 */
}
/* Add 버튼 */
@@ -54,9 +60,11 @@ h2 {
font-size: 1rem;
background-color: #000;
color: #fff;
- border: none;
+ border: none; /* Add 버튼은 테두리 없음 */
border-radius: 0;
cursor: pointer;
+ outline: none;
+ transition: background-color 0.2s ease; /* 호버 효과 부드럽게 */
}
.add-button-container button:hover {
@@ -80,9 +88,18 @@ h2 {
border: 1px solid #333; /* 얇은 테두리 */
border-radius: 0;
cursor: pointer;
+ outline: none;
+ transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
-.filter-buttons button:hover {
+/* 활성 필터 버튼 스타일 */
+.filter-buttons button.active {
+ background-color: #000; /* 활성 버튼은 배경 검정 */
+ color: #fff; /* 글자 흰색 */
+ border-color: #000;
+}
+
+.filter-buttons button:not(.active):hover { /* 활성 상태가 아닐 때만 호버 스타일 적용 */
background-color: #f0f0f0;
}
@@ -94,38 +111,53 @@ h2 {
text-align: left;
}
-/* 작업 목록 */
+/* 작업 목록 컨테이너 */
.task-list {
- margin-top: 10px;
+ /* margin-top: 10px; */
}
+/* 각 할 일 항목 (기본 & 편집 공통 스타일) */
.task-item {
- margin-bottom: 20px;
+ margin-bottom: 20px; /* 항목 하단 간격 */
+ border-bottom: 1px solid #eee; /* 항목 구분선 */
+ padding-bottom: 20px; /* 구분선과 내용 간 간격 */
}
-.task-row {
+.task-item:last-child {
+ border-bottom: none; /* 마지막 항목은 구분선 없음 */
+ padding-bottom: 0;
+}
+
+
+/* 기본 모드 (.task-item 안에 있을 때) */
+.task-item .task-row {
display: flex;
align-items: center;
- margin-bottom: 5px;
+ margin-bottom: 5px; /* 체크박스/이름과 버튼 간 간격 */
}
-.task-row input[type="checkbox"] {
+/* 체크박스 기본 스타일 */
+.task-item .task-row input[type="checkbox"] {
width: 20px;
height: 20px;
margin-right: 10px;
border: 2px solid #333;
border-radius: 0;
- appearance: none;
+ appearance: none; /* 기본 브라우저 스타일 제거 */
cursor: pointer;
+ flex-shrink: 0; /* 체크박스가 줄어들지 않도록 */
+ position: relative; /* 체크마크 위치 기준 */
+ outline: none;
}
-.task-row input[type="checkbox"]:checked {
+/* 체크박스 체크된 상태 스타일 */
+.task-item .task-row input[type="checkbox"]:checked {
background-color: #000;
border-color: #000;
- position: relative;
}
-.task-row input[type="checkbox"]:checked::after {
+/* 체크박스 체크마크 */
+.task-item .task-row input[type="checkbox"]:checked::after {
content: "✔";
color: #fff;
font-size: 14px;
@@ -135,36 +167,125 @@ h2 {
transform: translate(-50%, -50%);
}
-.task-row .task-name {
+/* 할 일 이름 */
+.task-item .task-row .task-name {
font-size: 1rem;
+ flex-grow: 1; /* 남은 공간 차지 */
+ word-break: break-word; /* 긴 단어 줄바꿈 */
+}
+
+/* 완료된 할 일 이름 스타일 */
+.task-item .task-row .task-name.completed {
+ text-decoration: line-through;
+ color: #888; /* 회색으로 변경 */
}
-.task-actions {
+
+/* Edit/Delete 버튼 컨테이너 (기본 모드 & 편집 모드 공통) */
+.task-item .task-actions {
display: flex;
- gap: 10px;
+ gap: 10px; /* 버튼 간 간격 */
}
-.task-actions button {
- flex: 1;
+/* Edit/Delete 버튼 기본 스타일 */
+.task-item .task-actions button {
+ flex: 1; /* 필터 버튼과 동일한 폭 */
padding: 5px 10px;
font-size: 0.9rem;
background-color: #fff;
color: #000;
- border: 1px solid #333;
+ border: 1px solid #333; /* 얇은 테두리 */
border-radius: 0;
cursor: pointer;
+ outline: none;
+ transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
-.task-actions button:hover {
+.task-item .task-actions button:hover {
background-color: #f0f0f0;
}
-.task-actions .button-delete {
- background-color: #ff0000;
- color: #fff;
-
+/* Delete 버튼 스타일 */
+.task-item .task-actions button:last-child {
+ background-color: #ff0000; /* 빨간색 배경 */
+ color: #fff; /* 흰색 글씨 */
+ border-color: #ff0000; /* 배경과 동일한 색 테두리 */
+}
+
+.task-item .task-actions button:last-child:hover {
+ background-color: #e60000; /* 호버 시 약간 어두운 빨간색 */
+ border-color: #e60000;
+}
+
+
+/* --- 👇 편집 모드 (Editing Mode) 스타일 --- */
+
+/* 편집 모드일 때 할 일 항목 컨테이너 레이아웃 */
+.task-item.editing {
+ display: flex; /* Flexbox 사용 */
+ flex-direction: column; /* 자식 요소를 세로로 쌓음 */
+ align-items: flex-start; /* 왼쪽 정렬 */
+}
+
+/* 편집 모드일 때 기본 .task-row (체크박스 + 이름) 숨기기 */
+.task-item.editing .task-row {
+ display: none;
+}
+
+/* 편집 모드 라벨 스타일 ("New name for...") */
+.task-item.editing .edit-label {
+ font-size: 1rem; /* task-name과 동일한 크기 */
+ margin-bottom: 5px; /* 라벨과 입력창 간 간격 */
+ font-weight: normal; /* 볼드 해제 (task-name은 볼드 아니었으므로) */
+}
+
+/* 편집 모드 입력창 스타일 */
+.task-item.editing input.edit-input {
+ width: 100%; /* 부모 컨테이너 폭에 맞춤 */
+ padding: 8px;
+ font-size: 1rem;
+ border: 2px solid #333;
+ border-radius: 0;
+ box-sizing: border-box;
+ margin-bottom: 10px; /* 입력창과 버튼 간 간격 */
+ outline: none; /* 포커스 시 기본 외곽선 제거 */
+}
+
+/* 편집 모드 버튼 컨테이너 스타일 (Cancel/Save) */
+.task-item.editing .task-actions {
+ display: flex; /* 버튼들은 Flex로 */
+ gap: 10px; /* 버튼 간 간격 */
+ width: 100%; /* 부모(task-item.editing) 너비에 맞춤 */
+}
+
+/* Cancel 버튼 스타일 */
+.task-item.editing .task-actions .cancel-button { /* 클래스 선택자 사용 */
+ flex: 1; /* 동일 폭 */
+ padding: 5px 10px;
+ font-size: 0.9rem;
+ background-color: #fff; /* 흰색 배경 */
+ color: #000; /* 검은색 글씨 */
+ border: 1px solid #333; /* 얇은 테두리 */
+ border-radius: 0;
+}
+.task-item.editing .task-actions .cancel-button:hover {
+ background-color: #f0f0f0;
+}
+
+/* Save 버튼 스타일 */
+.task-item.editing .task-actions .save-button { /* 클래스 선택자 사용 */
+ flex: 1; /* 동일 폭 */
+ padding: 5px 10px;
+ font-size: 0.9rem;
+ /* 👇 여기! Save 버튼 배경을 검정색으로 변경 */
+ background-color: #000; /* 검은색 배경 */
+ color: #fff; /* 글자색 흰색 유지 */
+ border: none; /* 테두리 없음 유지 */
+ /* 👆 여기까지 수정 */
+ border-radius: 0;
+}
+/* Save 버튼 호버 스타일 */
+.task-item.editing .task-actions .save-button:hover {
+ background-color: #333; /* 호버 시 약간 밝은 검정색 */
}
-.task-actions .button-delete:hover {
- background-color: #e60000;
-}
\ No newline at end of file
diff --git a/src/App.jsx b/src/App.jsx
index 755756d..91331d5 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,66 +1,44 @@
+// src/App.jsx - 라우팅 설정 담당
+import React from 'react';
+import { Routes, Route } from 'react-router-dom';
-import Header from "@/component/Header";
-import AddTodo from "@/component/AddTodo";
-import Category from "@/component/Category";
-import TodoList from "@/component/TodoList";
+// 라우팅할 페이지 컴포넌트들을 임포트합니다.
+// 아직 HomePage, LoginPage, SignupPage 파일이 없다면 이전에 제공된 코드로 src/pages 폴더에 생성해야 합니다.
+import HomePage from './pages/HomePage';
+import LoginPage from './pages/LoginPage';
+import SignupPage from './pages/SignupPage';
+// 이름을 변경하고 이동시킨 TodoPage 컴포넌트를 임포트합니다.
+import TodoPage from './pages/TodoPage';
-import "./App.css";
+import './App.css'; // App 전체에 적용될 스타일이 있다면 유지
function App() {
- const [tasks, setTasks] = useState([
- { name: "Eat", completed: true },
- { name: "Sleep", completed: false },
- { name: "Repeat", completed: false },
- ]);
- const [inputValue, setInputValue] = useState("");
- const [filter, setFilter] = useState("all");
+ return (
+ // 앱 전체 레이아웃 또는 전역 스타일을 위한 컨테이너
+
+ {/* App 전체에 적용될 헤더, 네비게이션 바 등은 Routes 바깥에 둘 수 있습니다. */}
+
Zero100 과제 - 5주차
+ 로그인/회원가입 구현하기 - ui 구현
- const addTask = () => {
- if (inputValue) {
- setTasks([...tasks, { name: inputValue, completed: false }]);
- setInputValue("");
- }
- };
+ {/* Routes 컴포넌트로 라우트를 정의 */}
+
+ {/* 루트 경로 ('/')는 HomePage 컴포넌트와 연결 */}
+ } />
- const toggleTask = (index) => {
- const updatedTasks = [...tasks];
- updatedTasks[index].completed = !updatedTasks[index].completed;
- setTasks(updatedTasks);
- };
+ {/* '/login' 경로는 LoginPage 컴포넌트와 연결 */}
+ } />
- const deleteTask = (index) => {
- const updatedTasks = tasks.filter((_, i) => i !== index);
- setTasks(updatedTasks);
- };
+ {/* '/signup' 경로는 SignupPage 컴포넌트와 연결 */}
+ } />
- const editTask = (index, newName) => {
- const updatedTasks = [...tasks];
- updatedTasks[index].name = newName;
- setTasks(updatedTasks);
- };
+ {/* '/todo' 경로는 이제 TodoPage (기존 App) 컴포넌트와 연결 */}
+ } />
- const filteredTasks = tasks.filter((task) => {
- if (filter === "all") return true;
- if (filter === "active") return !task.completed;
- if (filter === "completed") return task.completed;
- return true;
- });
+ {/* 정의되지 않은 경로에 대한 처리 */}
+ {/* 404 Not Found} /> */}
+
- return (
-
-
-
-
-
+ {/* App 전체에 적용될 푸터 등은 Routes 바깥에 둘 수 있습니다. */}
);
}
diff --git a/src/Mission-FE-Zero100 b/src/Mission-FE-Zero100
new file mode 160000
index 0000000..839460c
--- /dev/null
+++ b/src/Mission-FE-Zero100
@@ -0,0 +1 @@
+Subproject commit 839460c80639bc697cb6f3621879e9e8900adf57
diff --git a/src/component/AddTodo.jsx b/src/component/AddTodo.jsx
index 4207b6b..cfd0715 100644
--- a/src/component/AddTodo.jsx
+++ b/src/component/AddTodo.jsx
@@ -10,7 +10,9 @@ function AddTodo({ inputValue, setInputValue, addTask }) {
onChange={(e) => setInputValue(e.target.value)}
/>
-
+
+
+
);
}
diff --git a/src/component/ButtonComponent.jsx b/src/component/ButtonComponent.jsx
index 701db59..765a043 100644
--- a/src/component/ButtonComponent.jsx
+++ b/src/component/ButtonComponent.jsx
@@ -1,9 +1,10 @@
-function ButtonComponent({ label, onClick, type }) {
-
- const buttonClass = type === "add" ? "add-button-container" : "";
+import React from "react";
+// props 객체에서 className도 받아옵니다.
+function ButtonComponent({ label, onClick, className }) {
+ // 받은 className을