diff --git a/.prettierrc b/.prettierrc
deleted file mode 100644
index a124b9a7..00000000
--- a/.prettierrc
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "printWidth": 100,
- "tabWidth": 2,
- "trailingComma": "all",
- "singleQuote": true,
- "jsxSingleQuote": true,
- "semi": false
- }
\ No newline at end of file
diff --git a/README.md b/README.md
index a2f13c0b..4e61fad7 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
# ๐ฅ๏ธ Mission-FE-Zero100
FE Zero100 ๋ฏธ์
์ ์ํ ๋ ํฌ์งํ ๋ฆฌ์
๋๋ค.
diff --git a/eslint.config.js b/eslint.config.js
deleted file mode 100644
index b157c90c..00000000
--- a/eslint.config.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import js from '@eslint/js';
-import globals from 'globals';
-import react from 'eslint-plugin-react';
-import reactHooks from 'eslint-plugin-react-hooks';
-import reactRefresh from 'eslint-plugin-react-refresh';
-import prettier from 'eslint-config-prettier'; // Prettier ์ค์ ์ถ๊ฐ
-import prettierPlugin from 'eslint-plugin-prettier'; // Prettier ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ
-export default [
- { ignores: ['dist'] }, // 'dist' ๋๋ ํ ๋ฆฌ๋ ESLint ๊ฒ์ฌ๋ฅผ ๋ฌด์
- {
- files: ['**/*.{js,jsx}'], // ESLint๊ฐ ๊ฒ์ฌํ ํ์ผ ํ์ฅ์ ์ค์
- languageOptions: {
- ecmaVersion: 2020, // ECMAScript 2020 ์ง์
- globals: globals.browser, // ๋ธ๋ผ์ฐ์ ์ ์ญ ๋ณ์ ํ์ฉ
- parserOptions: {
- ecmaVersion: 'latest', // ์ต์ ECMAScript ๋ฒ์ ์ง์
- ecmaFeatures: { jsx: true }, // JSX ์ง์
- sourceType: 'module', // ECMAScript ๋ชจ๋ ์ฌ์ฉ
- },
- },
- settings: {
- react: { version: '18.3' }, // React ๋ฒ์ ๊ฐ์ง
- },
- plugins: {
- react, // React ESLint ํ๋ฌ๊ทธ์ธ
- 'react-hooks': reactHooks, // React Hooks ํ๋ฌ๊ทธ์ธ
- 'react-refresh': reactRefresh, // React Fast Refresh ํ๋ฌ๊ทธ์ธ
- prettier: prettierPlugin, // Prettier ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ
- },
- rules: {
- ...js.configs.recommended.rules, // ESLint ์ถ์ฒ ๊ท์น ์ ์ฉ
- ...react.configs.recommended.rules, // React ์ถ์ฒ ๊ท์น ์ ์ฉ
- ...react.configs['jsx-runtime'].rules, // JSX ๋ฐํ์ ๊ด๋ จ ๊ท์น
- ...reactHooks.configs.recommended.rules, // React Hooks ์ถ์ฒ ๊ท์น ์ ์ฉ
- 'react/jsx-no-target-blank': 'off', // target="_blank" ๋ณด์ ๊ฒฝ๊ณ ๋นํ์ฑํ
- 'react-refresh/only-export-components': [
- 'warn',
- { allowConstantExport: true },
- ],
- 'prettier/prettier': 'error', // Prettier ๊ท์น์ ์๋ฐํ๋ฉด ESLint์์ ์๋ฌ๋ก ์ฒ๋ฆฌ
- },
- },
-];
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index b77564a5..ad96620a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,8 @@
"version": "0.0.0",
"dependencies": {
"react": "^19.0.0",
- "react-dom": "^19.0.0"
+ "react-dom": "^19.0.0",
+ "react-router-dom": "^7.4.1"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
@@ -1339,6 +1340,12 @@
"@babel/types": "^7.20.7"
}
},
+ "node_modules/@types/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
@@ -1589,6 +1596,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2432,6 +2448,46 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.1.tgz",
+ "integrity": "sha512-Vmizn9ZNzxfh3cumddqv3kLOKvc7AskUT0dC1prTabhiEi0U4A33LmkDOJ79tXaeSqCqMBXBU/ySX88W85+EUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/cookie": "^0.6.0",
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0",
+ "turbo-stream": "2.4.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.4.1.tgz",
+ "integrity": "sha512-L3/4tig0Lvs6m6THK0HRV4eHUdpx0dlJasgCxXKnavwhh4tKYgpuZk75HRYNoRKDyDWi9QgzGXsQ1oQSBlWpAA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.4.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -2505,6 +2561,12 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -2564,6 +2626,12 @@
"node": ">=8"
}
},
+ "node_modules/turbo-stream": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
+ "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
+ "license": "ISC"
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/package.json b/package.json
index 4fffc473..c050a39c 100644
--- a/package.json
+++ b/package.json
@@ -8,13 +8,11 @@
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
-
-
-
},
"dependencies": {
"react": "^19.0.0",
- "react-dom": "^19.0.0"
+ "react-dom": "^19.0.0",
+ "react-router-dom": "^7.4.1"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
diff --git a/src/App.jsx b/src/App.jsx
index 9b836f3c..d82f27d3 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,23 +1,50 @@
-import "./index.css";
-import Text from "./component/Text";
-import Input from "./component/Input";
-import Button from "./component/Button";
-import Checkbox from "./component/Checkbox";
+import React from "react";
+import { BrowserRouter as Router, Routes, Route, useNavigate } from "react-router-dom";
+import TodoPage from "./component/TodoPage";
+import LoginPage from "./component/LoginPage";
+import SignupPage from "./component/SignupPage";
-function App() {
+function App(){
return (
-
- {/* text part */}
-
+
+
+ }/>
+ }/>
+ }/>
+ }/>
+
+
+ );
+}
+
+function Home(){
+ const navigate =useNavigate();
+
+ const buttonStyle = {
+ width: "200px",
+ padding: "10px 0",
+ margin: "20px auto",
+ display: "block",
+ backgroundColor: "#ddd",
+ border: "none",
+ borderRadius: "30px",
+ fontSize: "1.1rem",
+ fontWeight: "600",
+ };
+
+ const titleStyle = {
+ fontSize: "2rem",
+ fontWeight: "700",
+ marginBottom: "40px",
+ };
- {/* input part */}
-
- {/* button part */}
-
- {/* checkbox part */}
-
+ return(
+
+
Tayie's TODO
+
+
);
}
-export default App;
+export default App;
\ No newline at end of file
diff --git a/src/Blocks.jsx b/src/Blocks.jsx
deleted file mode 100644
index 9095b707..00000000
--- a/src/Blocks.jsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import styled from "styled-components";
-
-const Wrapper = styled.div`
-padding: 1rem;
-display: flex;
-flex-direction: row;
-align-items: flex-start;
-justify-content: flex-start;
-background-color: lightgrey;
-`;
-
-const Block = styled.div`
-padding: ${(props)=> props.padding};
-border: 1px solid black;
-border-radius: 1rem;
-background-color: ${(props) => props.backgroundColor};
-color: white;
-font-size: 2rem;
-font-weight: bold;
-text-align: center;
-`;
-
-const blockItems= [
- {
- label: "1",
- padding: "1rem",
- backgroundColor: "red",
- },
- {
- label: "2",
- padding: "3rem",
- backgroundColor: "green",
- },
- {
- label:"3",
- padding: "2rem",
- backgroundColor: "blue",
- },
-];
-
-function Blocks(props){
- return(
-
- {blockItems.map((blockItem) => {
- return (
-
- {blockItem.label}
-
- );
- })}
-
- );
-}
-
-export default Blocks;
\ No newline at end of file
diff --git a/src/component/AddTodo.jsx b/src/component/AddTodo.jsx
new file mode 100644
index 00000000..e855bb5a
--- /dev/null
+++ b/src/component/AddTodo.jsx
@@ -0,0 +1,59 @@
+import React, { useState } from 'react';
+import styled from "styled-components";
+
+const AddTodoContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+`;
+
+const StyledText = styled.h2`
+ text-align: center;
+ display: flex;
+`;
+
+const StyledInput = styled.input`
+ width: 500px;
+ padding: 14px;
+ border-radius: 0px;
+ margin-bottom: 8px;
+`;
+
+const StyledButton = styled.button`
+ background-color: black;
+ color: white;
+ width: 532px;
+ padding: 9px;
+ border: none;
+ border-radius: 0px;
+ margin-bottom: 8px;
+`;
+
+const AddTodo = ({ onAddTodo }) => {
+ const [inputValue, setInputValue] = useState("");
+
+ const handleInputChange = (e) => {
+ setInputValue(e.target.value);
+ };
+
+ const handleAddClick = () => {
+ onAddTodo(inputValue);
+ setInputValue("");
+ };
+
+ return(
+
+ What needs to be done?
+
+ Add
+
+ )
+}
+
+export default AddTodo;
\ No newline at end of file
diff --git a/src/component/Button.jsx b/src/component/Button.jsx
deleted file mode 100644
index 551f49c4..00000000
--- a/src/component/Button.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react'
-
-const Button = ({label, onClick}) => {
- return (
-
-
-
-
-
- )
-}
-
-export default Button;
diff --git a/src/component/Category.jsx b/src/component/Category.jsx
new file mode 100644
index 00000000..291e5d6b
--- /dev/null
+++ b/src/component/Category.jsx
@@ -0,0 +1,35 @@
+import React, { useState } from 'react';
+import styled from "styled-components";
+
+const CategoryContainer = styled.div`
+ display: flex;
+ justify-content: center;
+ gap: 8px;
+`;
+
+const StyledButton = styled.button`
+ width: 130px;
+ padding: 7px;
+ background-color: white;
+ border: 2px solid ${(props) => (props.active ? "black" : "#ccc")};
+ border-radius: 0px;
+ font-size: 14px;
+`;
+
+const Category = ({ activeCategory, setActiveCategory }) => {
+ return (
+
+ {["All", "Active", "Completed"].map((label) => (
+ setActiveCategory(label)}
+ >
+ {label}
+
+ ))}
+
+ );
+};
+
+export default Category;
\ No newline at end of file
diff --git a/src/component/Checkbox.jsx b/src/component/Checkbox.jsx
deleted file mode 100644
index e674f743..00000000
--- a/src/component/Checkbox.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react'
-
-const Checkbox = () => {
- return (
-
- )
-}
-
-export default Checkbox
diff --git a/src/component/Header.jsx b/src/component/Header.jsx
new file mode 100644
index 00000000..46bf9d3c
--- /dev/null
+++ b/src/component/Header.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import styled from "styled-components";
+
+const HeaderContainer = styled.text`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+`;
+
+const Header = () => {
+ return (
+
+ TodoMatic
+
+ );
+ };
+
+ export default Header
+
\ No newline at end of file
diff --git a/src/component/Input.jsx b/src/component/Input.jsx
deleted file mode 100644
index 0592b378..00000000
--- a/src/component/Input.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react'
-
-const Input = () => {
- return (
-
-
-
-
- )
-}
-
-export default Input
diff --git a/src/component/LoginPage.jsx b/src/component/LoginPage.jsx
new file mode 100644
index 00000000..35ed654f
--- /dev/null
+++ b/src/component/LoginPage.jsx
@@ -0,0 +1,97 @@
+import React from "react";
+import { useNavigate } from "react-router-dom";
+
+function LoginPage() {
+ const navigate = useNavigate();
+
+ return (
+
+
๋ก๊ทธ์ธ
+
+
+
+
navigate("/signup")}>
+ ํ์๊ฐ์
+
+
+ );
+}
+
+const styles = {
+ container: {
+ backgroundColor: "#f0f0f0",
+ height: "100vh",
+ display: "flex",
+ flexDirection: "column",
+ justifyContent: "center",
+ alignItems: "center",
+ fontFamily: "sans-serif",
+ },
+ title: {
+ fontSize: "2rem",
+ fontWeight: "700",
+ marginBottom: "40px",
+ },
+ formWrapper: {
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ gap: "20px",
+ },
+ inputContainer: {
+ display: "flex",
+ flexDirection: "column",
+ gap: "10px",
+ },
+ inputRow: {
+ display: "flex",
+ alignItems: "center",
+ },
+ label: {
+ width: "80px",
+ fontSize: "1rem",
+ fontWeight: "600",
+ textAlign: "right",
+ marginRight: "10px",
+ },
+ input: {
+ width: "200px",
+ padding: "8px",
+ fontSize: "1rem",
+ borderRadius: "5px",
+ border: "1px solid #ccc",
+ },
+ loginButton: {
+ backgroundColor: "#444",
+ color: "#fff",
+ padding: "30px 20px",
+ border: "none",
+ borderRadius: "6px",
+ fontSize: "1rem",
+ fontWeight: "600",
+ cursor: "pointer",
+ },
+ signupText: {
+ marginTop: "30px",
+ color: "#333",
+ fontSize: "1rem",
+ fontWeight: "600",
+ cursor: "pointer",
+ },
+};
+
+export default LoginPage;
diff --git a/src/component/SignupPage.jsx b/src/component/SignupPage.jsx
new file mode 100644
index 00000000..e00c348d
--- /dev/null
+++ b/src/component/SignupPage.jsx
@@ -0,0 +1,94 @@
+import React from "react";
+import { useNavigate } from "react-router-dom";
+
+function SignupPage() {
+ const navigate = useNavigate();
+
+ return (
+
+ );
+}
+
+const styles = {
+ container: {
+ backgroundColor: "#f0f0f0",
+ height: "100vh",
+ display: "flex",
+ flexDirection: "column",
+ justifyContent: "center",
+ alignItems: "center",
+ fontFamily: "sans-serif",
+ },
+ title: {
+ fontSize: "2rem",
+ fontWeight: "700",
+ marginBottom: "40px",
+ },
+ formWrapper: {
+ display: "flex",
+ flexDirection: "column", // ์์ ๋ ๋ถ๋ถ
+ alignItems: "center",
+ gap: "20px",
+ },
+ inputContainer: {
+ display: "flex",
+ flexDirection: "column",
+ gap: "15px",
+ },
+ inputRow: {
+ display: "flex",
+ alignItems: "center",
+ },
+ label: {
+ width: "80px",
+ fontSize: "1rem",
+ fontWeight: "600",
+ textAlign: "right",
+ marginRight: "10px",
+ },
+ input: {
+ width: "200px",
+ padding: "8px",
+ fontSize: "1rem",
+ borderRadius: "5px",
+ border: "1px solid #ccc",
+ },
+ signupButton: {
+ backgroundColor: "#444",
+ color: "#fff",
+ padding: "15px 20px",
+ border: "none",
+ borderRadius: "6px",
+ fontSize: "1.5rem",
+ fontWeight: "400",
+ cursor: "pointer",
+ marginTop: "20px",
+ width: "150px",
+ alignSelf: "center",
+ },
+};
+
+export default SignupPage;
diff --git a/src/component/Text.jsx b/src/component/Text.jsx
deleted file mode 100644
index 6fe9ec78..00000000
--- a/src/component/Text.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react'
-
-const Text = () => {
- return (
-
-
TodoMatic
- What needs to be done?
-
- )
-}
-
-export default Text
diff --git a/src/component/TodoList.jsx b/src/component/TodoList.jsx
new file mode 100644
index 00000000..3daff4c4
--- /dev/null
+++ b/src/component/TodoList.jsx
@@ -0,0 +1,198 @@
+import styled from "styled-components";
+import React, { useState } from 'react';
+
+const TodoListContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+`;
+
+const StyledText = styled.h2`
+ align-self: flex-start;
+ margin-left: 200px;
+`;
+
+const StyledCheckbox = styled.input.attrs({ type: 'checkbox' })`
+ appearance: none;
+ width: 40px;
+ height: 40px;
+ margin-right: 10px;
+ border: 2px solid black;
+ background-color: white;
+ position: relative;
+ margin-right: 10px;
+
+ &:checked::after {
+ content: '';
+ position: absolute;
+ top: 5px;
+ left: 12px;
+ width: 8px;
+ height: 16px;
+ border: solid black;
+ border-width: 0 4px 4px 0;
+ transform: rotate(45deg);
+ };
+`;
+
+const StyledButton = styled.button`
+ padding: 7px 80px;
+ font-size: 14px;
+ border: none;
+ border-radius: 0px;
+ margin: 5px;
+`;
+
+const EditButton = styled(StyledButton)`
+ background-color: white;
+ border: 1px solid black;
+`;
+
+const DeleteButton = styled(StyledButton)`
+ background-color: #d9534f;
+ color: white;
+`;
+
+const SaveButton = styled(StyledButton)`
+ background-color: black;
+ color: white;
+ `;
+
+const CancelButton = styled(StyledButton)`
+ background-color: white;
+ border: 1px, solid, black;
+ color: black;
+ `;
+
+const TaskItem = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ margin-bottom: 20px;
+`;
+
+const TaskTop = styled.div`
+ display: flex;
+ align-items: center;
+`;
+
+const TaskActions = styled.div`
+ display: flex;
+ margin-top: 5px;
+`;
+
+const TodoList = ({ todos, setTodos, activeCategory }) => {
+ const [editTexts, setEditTexts] = useState({});
+
+ const handleDelete = (id) => {
+ setTodos(todos.filter(todo => todo.id !== id));
+ };
+
+ const handleToggleComplete = (id) => {
+ setTodos(
+ todos.map(todo =>
+ todo.id === id ? { ...todo, completed: !todo.completed } : todo
+ )
+ );
+ };
+
+ const handleEdit = (id, currentText) => {
+ setEditTexts(prev => ({...prev, [id]:currentText}));
+ setTodos(
+ todos.map(todo =>
+ todo.id === id ? {...todo, isEditing: true}: todo
+ )
+ );
+ };
+
+ const handleSave =(id) => {
+ setTodos(
+ todos.map(todo =>
+ todo.id === id
+ ? { ...todo, text: editTexts[id], isEditing: false }
+ : todo
+ )
+ );
+ setEditTexts(prev => {
+ const newEditTexts = { ...prev };
+ delete newEditTexts[id];
+ return newEditTexts;
+ });
+ };
+
+ const handleCancel = (id) => {
+ setTodos(
+ todos.map(todo =>
+ todo.id === id ? { ...todo, isEditing: false } : todo
+ )
+ );
+ setEditTexts(prev => {
+ const newEditTexts = { ...prev };
+ delete newEditTexts[id];
+ return newEditTexts;
+ });
+ };
+
+ const handleEditChange = (id, newText) => {
+ setEditTexts(prev => ({ ...prev, [id]: newText }));
+ };
+
+ const filteredTodos = todos.filter(todo => {
+ if (activeCategory === "Active") return !todo.completed;
+ if (activeCategory === "Completed") return todo.completed;
+ return true;
+ });
+
+ return (
+
+ {todos.filter(todo => !todo.completed).length} tasks remaining
+
+ {filteredTodos.map(todo => (
+
+ {todo.isEditing ? (
+ <>
+
+
+ New name for {todo.text}
+
+
+ handleEditChange(todo.id, e.target.value)}
+ style={{ width: "400px", padding: "8px", fontSize: "16px" }}
+ />
+
+
+
+ handleCancel(todo.id)}>Cancel
+ handleSave(todo.id)}>Save
+
+ >
+ ) : (
+ <>
+
+ handleToggleComplete(todo.id)}
+ />
+
+ {todo.text}
+
+
+
+ handleEdit(todo.id, todo.text)}>Edit
+ handleDelete(todo.id)}>Delete
+
+ >
+ )}
+
+ ))}
+
+
+ );
+};
+
+export default TodoList;
+
diff --git a/src/component/TodoPage.jsx b/src/component/TodoPage.jsx
new file mode 100644
index 00000000..b0e23b77
--- /dev/null
+++ b/src/component/TodoPage.jsx
@@ -0,0 +1,62 @@
+import styled from "styled-components";
+import Header from "./Header";
+import AddTodo from "./AddTodo";
+import Category from "./Category";
+import TodoList from "./TodoList";
+import { useState } from "react";
+import { useEffect } from "react";
+
+const Container = styled.div`
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+ background-color: #f9f9f9;
+
+ @media (max-width: 768px) and (orientation: portrait) {
+ max-width: 90%;
+ padding: 1.5rem;
+ }
+
+ @media (max-width: 480px) and (orientation: portrait) {
+ padding: 1rem;
+ }
+`;
+
+function TodoPage() {
+ const [todos, setTodos] = useState([]);
+ const [isLoaded, setIsLoaded] = useState(false);
+ const [activeCategory, setActiveCategory] = useState("All");
+
+ useEffect(() => {
+ const savedTodos = localStorage.getItem("tasks");
+ if (savedTodos) {
+ setTodos(JSON.parse(savedTodos));
+ }
+ setIsLoaded(true);
+ }, []);
+
+ useEffect(() =>{
+ if (isLoaded) {
+ localStorage.setItem("tasks", JSON.stringify(todos));
+ }
+ }, [todos, isLoaded]);
+
+ const handleAddTodo = (text) => {
+ if (text.trim() === "") return;
+ const newTodo = { id: Date.now(), text, completed: false, isEditing: false };
+ setTodos([...todos, newTodo]);
+ };
+
+ if (!isLoaded) return
Loading...
;
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default TodoPage;