diff --git a/.codesandbox/workspace.json b/.codesandbox/workspace.json new file mode 100644 index 0000000..e7d06a2 --- /dev/null +++ b/.codesandbox/workspace.json @@ -0,0 +1,20 @@ +{ + "responsive-preview": { + "Mobile": [ + 320, + 675 + ], + "Tablet": [ + 1024, + 765 + ], + "Desktop": [ + 1400, + 800 + ], + "Desktop HD": [ + 1920, + 1080 + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..af3ca13 --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "react", + "version": "1.0.0", + "description": "React Kanban", + "keywords": [ + "react", + "starter" + ], + "main": "src/index.js", + "dependencies": { + "prop-types": "15.7.2", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-scripts": "4.0.0", + "usestate": "1.1.3" + }, + "devDependencies": { + "@babel/runtime": "7.13.8", + "typescript": "4.1.3" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..42ae2d2 --- /dev/null +++ b/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + React App + + + + +
+ + + + \ No newline at end of file diff --git a/src/App.js b/src/App.js new file mode 100644 index 0000000..5019bae --- /dev/null +++ b/src/App.js @@ -0,0 +1,77 @@ +import "./styles.css"; +import React, { useState } from "react"; +import NavBar from "./components/NavBar/NavBar"; +import TaskList from "./components/TaskList/TaskList"; + +let idAcc = 0; + +const generateId = () => { + idAcc = idAcc + 1; + return idAcc; +}; + +export default function App() { + const [tasks, setTasks] = useState([]); + + const addTask = (title, state) => { + const newTask = { + id: generateId(), + title, + state + }; + setTasks((existingTasks) => { + return [...existingTasks, newTask]; + }); + }; + + const updateTask = (id, title, state) => { + console.log("Update tasks sendo chamado dentro de APP"); + setTasks((existingTasks) => { + return existingTasks.map((task) => { + if (task.id === id) { + return { ...task, title, state }; + } else { + return task; + } + }); + }); + }; + + const deleteTask = (id) => { + setTasks((exitingTasks) => { + return exitingTasks.filter((task) => task.id !== id); + }); + }; + + return ( +
+ +
+ t.state === "Pendente")} + onTaskUpdate={updateTask} + onDeleteTask={deleteTask} + /> + t.state === "Fazendo")} + onTaskUpdate={updateTask} + onDeleteTask={deleteTask} + /> + t.state === "Completa")} + onTaskUpdate={updateTask} + onDeleteTask={deleteTask} + /> +
+
+ ); +} diff --git a/src/components/NavBar/NavBar.js b/src/components/NavBar/NavBar.js new file mode 100644 index 0000000..cffe381 --- /dev/null +++ b/src/components/NavBar/NavBar.js @@ -0,0 +1,10 @@ +import React from "react"; +import "./navbar.css"; + +export default function NavBar() { + return ( + + ); +} diff --git a/src/components/NavBar/navbar.css b/src/components/NavBar/navbar.css new file mode 100644 index 0000000..fa2588f --- /dev/null +++ b/src/components/NavBar/navbar.css @@ -0,0 +1,7 @@ +.navbar { + display: flex; + background-color: rgba(0, 0, 0, 0.3); + padding: 8px; + color: white; + font-weight: bold; +} diff --git a/src/components/TaskItem/TaskItem.js b/src/components/TaskItem/TaskItem.js new file mode 100644 index 0000000..3990dd6 --- /dev/null +++ b/src/components/TaskItem/TaskItem.js @@ -0,0 +1,66 @@ +import React, { useState } from "react"; +import PropTypes from "prop-types"; + +import "./task-item.css"; + +export default function TaskItem({ + id, + title, + taskState, + onTaskUpdate, + onDeleteTask +}) { + const [isEditing, setIsEditing] = useState(false); + const [editableTitle, setEditableTitle] = useState(title); + + const onTitleChange = (event) => { + const newTitle = event.target.value; + setEditableTitle(newTitle); + onTaskUpdate(id, newTitle, taskState); + }; + + const onKeyPress = (event) => { + if (event.key === "Enter") { + setIsEditing(false); + if (editableTitle.length === 0) { + onDeleteTask(id); + } + } + }; + + const onTaskStateChange = (event) => { + onTaskUpdate(id, title, event.target.value); + }; + + if (isEditing) { + return ( +
+ +
+ ); + } else { + return ( +
+
setIsEditing(true)}>{editableTitle}
+ +
+ ); + } +} + +TaskItem.propTypes = { + id: PropTypes.number.isRequired, + title: PropTypes.string.isRequired, + taskState: PropTypes.string.isRequired, + onTaskUpdate: PropTypes.func.isRequired, + onDeleteTask: PropTypes.func.isRequired +}; diff --git a/src/components/TaskItem/task-item.css b/src/components/TaskItem/task-item.css new file mode 100644 index 0000000..7344587 --- /dev/null +++ b/src/components/TaskItem/task-item.css @@ -0,0 +1,24 @@ +.task-item { + background-color: #fff; + border-radius: 3px; + box-shadow: 0 1px 0 rgba(9, 30, 66, 0.25); + cursor: pointer; + margin-bottom: 8px; + width: 100%; + padding: 8px 4px; + color: #222; + font-size: 14px; +} + +.task-item input[type="text"] { + border: none; + font-size: 14px; + display: block; + width: 100%; +} + +.task-item select { + display: block; + width: 100%; + margin-top: 8px; +} diff --git a/src/components/TaskList/TaskList.js b/src/components/TaskList/TaskList.js new file mode 100644 index 0000000..dc6addb --- /dev/null +++ b/src/components/TaskList/TaskList.js @@ -0,0 +1,50 @@ +import React from "react"; +import "./task-list.css"; +import PropTypes from "prop-types"; + +import TaskItem from "../TaskItem/TaskItem"; + +export default function TaskList({ + title, + taskState, + onAddTask, + tasks, + onTaskUpdate, + onDeleteTask +}) { + const addTask = () => { + onAddTask("Nova Tarefa", taskState); + }; + + return ( +
+
{title}
+
+ {tasks.map((task) => { + return ( + + ); + })} + {tasks.length === 0 &&
Lista Vazia
} + +
+
+ ); +} + +TaskList.propTypes = { + title: PropTypes.string.isRequired, + onAddTask: PropTypes.func.isRequired, + tasks: PropTypes.array.isRequired, + onTaskUpdate: PropTypes.func.isRequired, + onDeleteTask: PropTypes.func.isRequired +}; diff --git a/src/components/TaskList/task-list.css b/src/components/TaskList/task-list.css new file mode 100644 index 0000000..d2fa515 --- /dev/null +++ b/src/components/TaskList/task-list.css @@ -0,0 +1,49 @@ +.tasklist { + padding: 8px; + background-color: #5797b9; + border-radius: 2px; +} + +.tasklist .title { + padding: 4px; + font-weight: bold; + background-color: rgba(0, 0, 0, 0.1); + text-align: center; +} + +.tasklist .content { + padding: 16px 4px; + display: flex; + flex-direction: column; +} + +.tasklist .content .empty-list { + text-align: center; + border: 1px dashed white; + border-radius: 4px; + padding: 4px; +} + +.tasklist .btn { + margin-top: 8px; + padding: 8px; + display: flex; + justify-content: center; + background: none; + border: none; + border-radius: 3px; + color: white; + background: #00b8d4; + transition: background-color 0.3s; +} + +.tasklist .btn:hover { + background-color: #0091a8; + cursor: pointer; +} + +.tasklist .btn img { + width: 15px; + height: 15px; + margin-right: 4px; +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..d65892e --- /dev/null +++ b/src/index.js @@ -0,0 +1,12 @@ +import { StrictMode } from "react"; +import ReactDOM from "react-dom"; + +import App from "./App"; + +const rootElement = document.getElementById("root"); +ReactDOM.render( + + + , + rootElement +); diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 0000000..05b8af0 --- /dev/null +++ b/src/styles.css @@ -0,0 +1,55 @@ +/* Minimo CSS Reset */ +html { + box-sizing: border-box; + font-size: 16px; +} + +html, +body { + height: 100%; + min-height: 100vh; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body, +h1, +h2, +h3, +h4, +h5, +h6, +p, +ol, +ul { + margin: 0; + padding: 0; + font-weight: normal; +} + +img { + max-width: 100%; + height: auto; +} + +.App { + font-family: sans-serif; + background-color: #0079bf; + height: 100%; + min-height: 100vh; + color: white; +} + +.App .container { + width: 100%; + max-width: 800px; + margin: auto; + padding: 8px; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-gap: 8px; +}