diff --git a/frontend_training/package.json b/frontend_training/package.json index 780124b..2ac757f 100644 --- a/frontend_training/package.json +++ b/frontend_training/package.json @@ -11,7 +11,8 @@ }, "dependencies": { "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "uuid": "^11.0.5" }, "devDependencies": { "@eslint/js": "^9.17.0", diff --git a/frontend_training/pnpm-lock.yaml b/frontend_training/pnpm-lock.yaml index 8295f94..53d495c 100644 --- a/frontend_training/pnpm-lock.yaml +++ b/frontend_training/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + uuid: + specifier: ^11.0.5 + version: 11.0.5 devDependencies: '@eslint/js': specifier: ^9.17.0 @@ -916,6 +919,10 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uuid@11.0.5: + resolution: {integrity: sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==} + hasBin: true + vite@6.0.11: resolution: {integrity: sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1748,6 +1755,8 @@ snapshots: dependencies: punycode: 2.3.1 + uuid@11.0.5: {} + vite@6.0.11: dependencies: esbuild: 0.24.2 diff --git a/frontend_training/src/App.css b/frontend_training/src/App.css index cce452c..c89219f 100644 --- a/frontend_training/src/App.css +++ b/frontend_training/src/App.css @@ -6,3 +6,138 @@ flex-direction: column; align-items: center; } + +.inputForm { + width: 600px; + display: flex; + align-items: center; + gap: 8px; + height: 38px; +} + +.input { + width: 100%; + height: 100%; + padding: 0 14px; + color: #000; + border: 1px solid rgb(0 0 0 / 20%); + border-radius: 4px; +} + +.todoList { + display: flex; + flex-direction: column; + gap: 20px; +} + +.todoItem { + display: flex; + gap: 30px; + align-items: center; +} + +.addButton { + border-radius: 4px; + width: 60px; + height: 100%; + font-size: 13px; + font-weight: 600; + line-height: 18px; + color: #fff; + background-color: #000; + border: 1px solid rgb(0 0 0 / 20%); + border-radius: 4px; + cursor: pointer; + + /* ホバー時のスタイル */ + &:hover { + background-color: rgb(0 0 0 / 70%); + } + + /* ボタン押下時のスタイル */ + &:active { + background-color: rgb(0 0 0 / 40%); + } +} + +.completeButton { + border-radius: 4px; + width: 60px; + height: 100%; + font-size: 13px; + font-weight: 600; + color: #fff; + background-color: #008000; + border: 1px solid rgb(0 128 0 / 20%); + cursor: pointer; + + /* ホバー時のスタイル */ + &:hover { + background-color: rgb(0 128 0 / 70%); + } + + /* ボタン押下時のスタイル */ + &:active { + background-color: rgb(0 128 0 / 40%); + } +} + +.editItem { + display: flex; + gap: 30px; + align-items: center; + height: 25px; +} + +.actionButtons { + width: 100%; + height: 100%; + display: flex; + gap: 5px; +} + +.updateButton { + border-radius: 4px; + width: fit-content; + height: 100%; + font-size: 13px; + font-weight: 600; + line-height: 18px; + color: #fff; + background-color: #007bff; + border: 1px solid rgba(0, 123, 255, 0.2); + cursor: pointer; + + /* ホバー時のスタイル */ + &:hover { + background-color: rgba(0, 123, 255, 0.7); + } + + /* ボタン押下時のスタイル */ + &:active { + background-color: rgba(0, 123, 255, 0.4); + } +} + +.cancelButton { + border-radius: 4px; + width: fit-content; + height: 100%; + font-size: 13px; + font-weight: 600; + line-height: 18px; + color: #fff; + background-color: #dc3545; + border: 1px solid rgba(220, 53, 69, 0.2); + cursor: pointer; + + /* ホバー時のスタイル */ + &:hover { + background-color: rgba(220, 53, 69, 0.7); + } + + /* ボタン押下時のスタイル */ + &:active { + background-color: rgba(220, 53, 69, 0.4); + } +} diff --git a/frontend_training/src/App.tsx b/frontend_training/src/App.tsx index 200cfb8..b725a6d 100644 --- a/frontend_training/src/App.tsx +++ b/frontend_training/src/App.tsx @@ -1,12 +1,153 @@ -import './App.css' +import { useState } from "react"; +import { v4 as uuidv4 } from "uuid"; +import "./App.css"; + +type TodoItem = { + id: string; + text: string; + isCompleted: boolean; + isEdit: boolean; +}; function App() { + const [inputValue, setInputValue] = useState(""); + const [todoList, setTodoList] = useState([]); + + const filteredTodoList = todoList.filter((todo) => !todo.isCompleted); return ( <>

TODOアプリ

+
+ { + setInputValue(event.target.value); + }} + /> + +
+ - ) + ); } -export default App +export default App; + +function EditTodo({ + todo, + setTodoList, +}: { + todo: TodoItem; + setTodoList: React.Dispatch>; +}) { + const [inputValue, setInputValue] = useState(todo.text); + + return ( +
+ { + setInputValue(event.target.value); + }} + className="input" + /> +
+ + +
+
+ ); +}