From 8b67f0355705523237d411662aa8e0df9fb8f1b5 Mon Sep 17 00:00:00 2001 From: Jonash189 Date: Sun, 24 Nov 2024 17:48:16 +0100 Subject: [PATCH 01/15] adding styling to the label and making sure accessibilty is at 100%. --- package-lock.json | 220 ++++++++++++++++++++++++++++++--- package.json | 7 +- src/App.jsx | 16 ++- src/Page/MyToDoListPage.jsx | 64 ++++++++++ src/components/AddToDoForm.jsx | 71 +++++++++++ src/components/ToDoList.jsx | 78 ++++++++++++ src/components/counter.jsx | 12 ++ src/index.css | 5 + src/main.jsx | 2 +- src/stores/Store.js | 36 ++++++ 10 files changed, 489 insertions(+), 22 deletions(-) create mode 100644 src/Page/MyToDoListPage.jsx create mode 100644 src/components/AddToDoForm.jsx create mode 100644 src/components/ToDoList.jsx create mode 100644 src/components/counter.jsx create mode 100644 src/stores/Store.js diff --git a/package-lock.json b/package-lock.json index 5c1b936d..8ddffb5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,14 @@ "name": "project-todos-context", "version": "0.0.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.1", + "@fortawesome/free-solid-svg-icons": "^6.7.1", + "@fortawesome/react-fontawesome": "^0.2.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.18.0" + "react-router-dom": "^6.18.0", + "styled-components": "^6.1.13", + "zustand": "^5.0.1" }, "devDependencies": { "@types/react": "^18.2.15", @@ -346,6 +351,27 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, "node_modules/@esbuild/darwin-arm64": { "version": "0.18.20", "cpu": [ @@ -427,6 +453,52 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.1.tgz", + "integrity": "sha512-gbDz3TwRrIPT3i0cDfujhshnXO9z03IT1UKRIVi/VEjpNHtSBIP2o5XSm+e816FzzCFEzAxPw09Z13n20PaQJQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.1.tgz", + "integrity": "sha512-8dBIHbfsKlCk2jHQ9PoRBg2Z+4TwyE3vZICSnoDlnsHA6SiMlTwfmW6yX0lHsRmWJugkeb92sA0hZdkXJhuz+g==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.1.tgz", + "integrity": "sha512-BTKc0b0mgjWZ2UDKVgmwaE0qt0cZs6ITcDgjrti5f/ki7aF5zs+N91V6hitGo3TItCFtnKg6cUVGdTmBFICFRg==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.13", "dev": true, @@ -578,12 +650,12 @@ }, "node_modules/@types/prop-types": { "version": "15.7.10", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.2.37", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -601,7 +673,13 @@ }, "node_modules/@types/scheduler": { "version": "0.16.6", - "dev": true, + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", + "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", "license": "MIT" }, "node_modules/@ungap/structured-clone": { @@ -866,6 +944,15 @@ "node": ">=6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001561", "dev": true, @@ -934,9 +1021,30 @@ "node": ">= 8" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/csstype": { - "version": "3.1.2", - "dev": true, + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, "node_modules/debug": { @@ -2255,7 +2363,6 @@ }, "node_modules/nanoid": { "version": "3.3.7", - "dev": true, "funding": [ { "type": "github", @@ -2282,7 +2389,6 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2472,12 +2578,12 @@ }, "node_modules/picocolors": { "version": "1.0.0", - "dev": true, "license": "ISC" }, "node_modules/postcss": { - "version": "8.4.31", - "dev": true, + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -2494,14 +2600,20 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "dev": true, @@ -2512,7 +2624,6 @@ }, "node_modules/prop-types": { "version": "15.8.1", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -2570,7 +2681,6 @@ }, "node_modules/react-is": { "version": "16.13.1", - "dev": true, "license": "MIT" }, "node_modules/react-refresh": { @@ -2800,6 +2910,12 @@ "node": ">= 0.4" } }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "dev": true, @@ -2833,8 +2949,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -2923,6 +3040,40 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/styled-components": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", + "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.38", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "5.5.0", "dev": true, @@ -2958,6 +3109,12 @@ "node": ">=4" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "dev": true, @@ -3253,6 +3410,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.1.tgz", + "integrity": "sha512-pRET7Lao2z+n5R/HduXMio35TncTlSW68WsYBq2Lg1ASspsNGjpwLAsij3RpouyV6+kHMwwwzP0bZPD70/Jx/w==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index a23290e8..a53bf1ed 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,14 @@ "preview": "vite preview" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.1", + "@fortawesome/free-solid-svg-icons": "^6.7.1", + "@fortawesome/react-fontawesome": "^0.2.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.18.0" + "react-router-dom": "^6.18.0", + "styled-components": "^6.1.13", + "zustand": "^5.0.1" }, "devDependencies": { "@types/react": "^18.2.15", diff --git a/src/App.jsx b/src/App.jsx index 496ab1b1..a7172ed1 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,3 +1,13 @@ -export const App = () => { - return
Find me in App.jsx!
; -}; +import MyToDoListPage from "./Page/MyToDoListPage"; + +function App() { // Huvudkomponenten för appen. + return ( +
{/* Ett omslutande `
` för att strukturera innehållet på sidan. */} + + {/* Visar listan över alla uppgifter med hjälp av TodoList-komponenten. */} + +
+ ); +} + +export default App; // Exporterar App-komponenten så den kan användas i index.js. diff --git a/src/Page/MyToDoListPage.jsx b/src/Page/MyToDoListPage.jsx new file mode 100644 index 00000000..445993d0 --- /dev/null +++ b/src/Page/MyToDoListPage.jsx @@ -0,0 +1,64 @@ +import TodoList from '../components/TodoList'; +import AddTodoForm from '../components/AddTodoForm'; +import Counter from '../components/Counter'; +import styled from "styled-components"; + +const StyledContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: #4c657e; + color: #fff; + width: 100vw; + height: 100vh; + padding: 20px; + box-sizing: border-box; + border-radius: 100px; + overflow: hidden; + + .content { + width: 100%; + height: 100%; + overflow-y: auto; + padding: 10px; + } + + @media (min-width: 1024px) { + width: 36vw; + height: 70vh; + padding: 40px; + border-radius: 30px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } +`; + +const StyledFormContainer = styled.div` + position: sticky; + bottom: 0; + width: 100%; + background-color: #4c657e; + padding: 10px 15px; + + z-index: 1; +`; + +export const MyToDoListPage = () => { + return ( + +

My To-Do List

+
+ +
+ + + + +
+ ); +}; + +export default MyToDoListPage; diff --git a/src/components/AddToDoForm.jsx b/src/components/AddToDoForm.jsx new file mode 100644 index 00000000..4a7012b9 --- /dev/null +++ b/src/components/AddToDoForm.jsx @@ -0,0 +1,71 @@ +import React, { useState } from "react"; +import useTodoStore from "../stores/Store"; +import styled from "styled-components"; + + +const StyledForm = styled.form` + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + margin-top: 20px; +`; + +const StyledInput = styled.input` + width: 100%; + max-width: 400px; + padding: 10px 15px; + font-size: 16px; + border: 2px solid rgba(255, 255, 255, 0.2); + border-radius: 20px; + outline: none; + background: #f9f9f9; + color: #333; + + &:focus { + border-color: #007bff; + } +`; + +const StyledButton = styled.button` + padding: 10px 20px; + font-size: 16px; + color: #fff; + background-color: black; + border: none; + border-radius: 20px; + cursor: pointer; + transition: background-color 0.3s ease; + + &:hover { + background-color: #d9363e; + } +`; + + +function AddTodoForm() { + const [text, setText] = useState(""); + const addTodo = useTodoStore((state) => state.addTodo); + + const handleSubmit = (e) => { + e.preventDefault(); + if (text.trim()) { + addTodo(text); + setText(""); + } + }; + + return ( + + setText(e.target.value)} + placeholder="Add a new task.." + /> + Add + + ); +} + +export default AddTodoForm; diff --git a/src/components/ToDoList.jsx b/src/components/ToDoList.jsx new file mode 100644 index 00000000..f371e110 --- /dev/null +++ b/src/components/ToDoList.jsx @@ -0,0 +1,78 @@ +import React from "react"; +import styled from "styled-components"; +import useTodoStore from "../stores/Store"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faTrash } from "@fortawesome/free-solid-svg-icons"; + + +const List = styled.ul` + list-style: none; + padding: 0; + margin: 20px auto; + max-width: 600px; + color: black; +`; + +const ListItem = styled.li` + display: flex; + align-items: center; + justify-content: space-between; + background-color: #f9f9f9; + padding: 10px 15px; + margin-bottom: 10px; + border-radius: 10px; + box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.1); +`; + +const Label = styled.label` + display: flex; + align-items: center; + gap: 10px; + font-size: 16px; + text-decoration: ${(props) => (props.completed ? "line-through" : "none")}; + color: ${(props) => (props.completed ? "#000000" : "#010101")}; +`; + +const Checkbox = styled.input` + cursor: pointer; +`; + +const RemoveIcon = styled(FontAwesomeIcon)` + color: black; + font-size: 18px; + cursor: pointer; + transition: color 0.3s ease; + + &:hover { + color: #d9363e; + } +`; + +function TodoList() { + const todos = useTodoStore((state) => state.todos); + const toggleTodo = useTodoStore((state) => state.toggleTodo); + const removeTodo = useTodoStore((state) => state.removeTodo); + + return ( + + {todos.map((todo) => ( + + + removeTodo(todo.id)} + /> + + ))} + + ); +} + +export default TodoList; diff --git a/src/components/counter.jsx b/src/components/counter.jsx new file mode 100644 index 00000000..10f335af --- /dev/null +++ b/src/components/counter.jsx @@ -0,0 +1,12 @@ +// counter.jsx + +import useTodoStore from "../stores/Store"; + +function Counter() { + const todos = useTodoStore((state) => state.todos); + const uncompletedCount = todos.filter((todo) => !todo.completed).length; + + return

Uncompleted tasks: {uncompletedCount}

; +} + +export default Counter; diff --git a/src/index.css b/src/index.css index 4669a352..d9b57f51 100644 --- a/src/index.css +++ b/src/index.css @@ -11,4 +11,9 @@ body { sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; +} + +:root { + + background-color: #36413d; } \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx index 51294f39..b91620d3 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,6 +1,6 @@ import React from "react"; import ReactDOM from "react-dom/client"; -import { App } from "./App.jsx"; +import App from "./App.jsx"; import "./index.css"; ReactDOM.createRoot(document.getElementById("root")).render( diff --git a/src/stores/Store.js b/src/stores/Store.js new file mode 100644 index 00000000..2554ec75 --- /dev/null +++ b/src/stores/Store.js @@ -0,0 +1,36 @@ +// Store.jsx + +import { create } from 'zustand'; + +const useTodoStore = create((set) => ({ // Creates a store using `create`. The function takes `set`, used to update the state. + + todos: [ // Defines the initial state, an array of objects representing tasks. + { id: "1", text: "Buy groceries", completed: false }, // Task 1 + { id: "2", text: "Walk the dog", completed: true }, // Task 2 + ], + + addTodo: (text) => // Function to add a new task. + set((state) => ({ // Updates the state using `set`. + todos: [...state.todos, { id: Date.now().toString(), text, completed: false }], + // Copies existing tasks (`...state.todos`) and adds a new task: + // - `id`: Created with `Date.now()` to ensure uniqueness. + // - `text`: The text passed in from the form. + // - `completed`: Defaults to `false` as new tasks are always incomplete. + })), + + removeTodo: (id) => // Function to remove a task. + set((state) => ({ // Updates the state using `set`. + todos: state.todos.filter((todo) => todo.id !== id), // Filters out the task with the matching `id`. + })), + + toggleTodo: (id) => // Function to toggle between `completed: true` and `completed: false`. + set((state) => ({ // Updates the state using `set`. + todos: state.todos.map((todo) => // Iterates through all tasks. + todo.id === id // If the task's ID matches the given ID: + ? { ...todo, completed: !todo.completed } // Toggle the `completed` property. + : todo // If the ID doesn't match, return the task as is. + ), + })), +})); + +export default useTodoStore; From b2a246b535e672191f3a4e2b8f2154a11f12fff4 Mon Sep 17 00:00:00 2001 From: Jonash189 Date: Sun, 24 Nov 2024 17:58:19 +0100 Subject: [PATCH 02/15] Fixing naming of ToDoList --- src/App.jsx | 10 ++++------ src/Page/MyToDoListPage.jsx | 4 ++-- src/components/ToDoList.jsx | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index a7172ed1..6eab6be2 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,13 +1,11 @@ import MyToDoListPage from "./Page/MyToDoListPage"; -function App() { // Huvudkomponenten för appen. +function App() { return ( -
{/* Ett omslutande `
` för att strukturera innehållet på sidan. */} - - {/* Visar listan över alla uppgifter med hjälp av TodoList-komponenten. */} - +
+
); } -export default App; // Exporterar App-komponenten så den kan användas i index.js. +export default App; diff --git a/src/Page/MyToDoListPage.jsx b/src/Page/MyToDoListPage.jsx index 445993d0..76ea0fb1 100644 --- a/src/Page/MyToDoListPage.jsx +++ b/src/Page/MyToDoListPage.jsx @@ -1,4 +1,4 @@ -import TodoList from '../components/TodoList'; +import ToDoList from '../components/ToDoList'; import AddTodoForm from '../components/AddTodoForm'; import Counter from '../components/Counter'; import styled from "styled-components"; @@ -51,7 +51,7 @@ export const MyToDoListPage = () => {

My To-Do List

- +
diff --git a/src/components/ToDoList.jsx b/src/components/ToDoList.jsx index f371e110..d39a1bc0 100644 --- a/src/components/ToDoList.jsx +++ b/src/components/ToDoList.jsx @@ -48,7 +48,7 @@ const RemoveIcon = styled(FontAwesomeIcon)` } `; -function TodoList() { +function ToDoList() { const todos = useTodoStore((state) => state.todos); const toggleTodo = useTodoStore((state) => state.toggleTodo); const removeTodo = useTodoStore((state) => state.removeTodo); @@ -75,4 +75,4 @@ function TodoList() { ); } -export default TodoList; +export default ToDoList; From 67b91ac4fe03d7192763abe9ca60a1fbc7321e33 Mon Sep 17 00:00:00 2001 From: Jonash189 Date: Sun, 24 Nov 2024 18:08:56 +0100 Subject: [PATCH 03/15] Fixing naming bugs --- src/Page/MyToDoListPage.jsx | 6 +++--- src/components/AddToDoForm.jsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Page/MyToDoListPage.jsx b/src/Page/MyToDoListPage.jsx index 76ea0fb1..c412cd90 100644 --- a/src/Page/MyToDoListPage.jsx +++ b/src/Page/MyToDoListPage.jsx @@ -1,6 +1,6 @@ import ToDoList from '../components/ToDoList'; -import AddTodoForm from '../components/AddTodoForm'; -import Counter from '../components/Counter'; +import AddToDoForm from '../components/AddToDoForm'; +import Counter from '../components/counter'; import styled from "styled-components"; const StyledContainer = styled.div` @@ -54,7 +54,7 @@ export const MyToDoListPage = () => {
- + diff --git a/src/components/AddToDoForm.jsx b/src/components/AddToDoForm.jsx index 4a7012b9..b43b5052 100644 --- a/src/components/AddToDoForm.jsx +++ b/src/components/AddToDoForm.jsx @@ -43,7 +43,7 @@ const StyledButton = styled.button` `; -function AddTodoForm() { +function AddToDoForm() { const [text, setText] = useState(""); const addTodo = useTodoStore((state) => state.addTodo); @@ -68,4 +68,4 @@ function AddTodoForm() { ); } -export default AddTodoForm; +export default AddToDoForm; From e553afd4e09b9f316ab0e46be45107d771a61e1f Mon Sep 17 00:00:00 2001 From: Jonash189 Date: Thu, 28 Nov 2024 15:05:31 +0100 Subject: [PATCH 04/15] Implemented all requested changes to improve code clarity and quality. --- src/Page/MyToDoListPage.jsx | 21 ++++++++++++--------- src/components/AddToDoForm.jsx | 6 +++--- src/components/ToDoList.jsx | 5 ++--- src/components/counter.jsx | 4 ++-- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Page/MyToDoListPage.jsx b/src/Page/MyToDoListPage.jsx index c412cd90..1e15f9d9 100644 --- a/src/Page/MyToDoListPage.jsx +++ b/src/Page/MyToDoListPage.jsx @@ -17,12 +17,6 @@ const StyledContainer = styled.div` border-radius: 100px; overflow: hidden; - .content { - width: 100%; - height: 100%; - overflow-y: auto; - padding: 10px; - } @media (min-width: 1024px) { width: 36vw; @@ -36,6 +30,15 @@ const StyledContainer = styled.div` } `; +const StyledToDoList = styled.div` +width: 100%; +height: 100 %; +overflow - y: auto; +padding: 10px; +`; + + + const StyledFormContainer = styled.div` position: sticky; bottom: 0; @@ -46,13 +49,13 @@ const StyledFormContainer = styled.div` z-index: 1; `; -export const MyToDoListPage = () => { +const MyToDoListPage = () => { return (

My To-Do List

-
+ -
+ diff --git a/src/components/AddToDoForm.jsx b/src/components/AddToDoForm.jsx index b43b5052..e2f55328 100644 --- a/src/components/AddToDoForm.jsx +++ b/src/components/AddToDoForm.jsx @@ -1,5 +1,5 @@ -import React, { useState } from "react"; -import useTodoStore from "../stores/Store"; +import { useState } from "react"; +import useTodoStore from "../stores/store"; import styled from "styled-components"; @@ -43,7 +43,7 @@ const StyledButton = styled.button` `; -function AddToDoForm() { +const AddToDoForm = () => { const [text, setText] = useState(""); const addTodo = useTodoStore((state) => state.addTodo); diff --git a/src/components/ToDoList.jsx b/src/components/ToDoList.jsx index d39a1bc0..6948336c 100644 --- a/src/components/ToDoList.jsx +++ b/src/components/ToDoList.jsx @@ -1,6 +1,5 @@ -import React from "react"; import styled from "styled-components"; -import useTodoStore from "../stores/Store"; +import useTodoStore from "../stores/store"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faTrash } from "@fortawesome/free-solid-svg-icons"; @@ -48,7 +47,7 @@ const RemoveIcon = styled(FontAwesomeIcon)` } `; -function ToDoList() { +const ToDoList = () => { const todos = useTodoStore((state) => state.todos); const toggleTodo = useTodoStore((state) => state.toggleTodo); const removeTodo = useTodoStore((state) => state.removeTodo); diff --git a/src/components/counter.jsx b/src/components/counter.jsx index 10f335af..a39a37aa 100644 --- a/src/components/counter.jsx +++ b/src/components/counter.jsx @@ -1,8 +1,8 @@ // counter.jsx -import useTodoStore from "../stores/Store"; +import useTodoStore from "../stores/store"; -function Counter() { +const Counter = () => { const todos = useTodoStore((state) => state.todos); const uncompletedCount = todos.filter((todo) => !todo.completed).length; From b2e3d4ff46341ea1aa0d561e44e4b0f9a0bd3542 Mon Sep 17 00:00:00 2001 From: Jonash189 Date: Thu, 28 Nov 2024 15:12:34 +0100 Subject: [PATCH 05/15] Pushing to git --- src/Page/MyToDoListPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Page/MyToDoListPage.jsx b/src/Page/MyToDoListPage.jsx index 1e15f9d9..693b14bf 100644 --- a/src/Page/MyToDoListPage.jsx +++ b/src/Page/MyToDoListPage.jsx @@ -1,6 +1,6 @@ import ToDoList from '../components/ToDoList'; import AddToDoForm from '../components/AddToDoForm'; -import Counter from '../components/counter'; +import Counter from '../components/Counter'; import styled from "styled-components"; const StyledContainer = styled.div` From 02e3e1fae6ae29d9b2d338b4031b9b8ca2e1749b Mon Sep 17 00:00:00 2001 From: Jonash189 Date: Thu, 28 Nov 2024 15:37:47 +0100 Subject: [PATCH 06/15] Installing typescript --- package-lock.json | 33 +++++++++++++++++++++++---------- package.json | 5 +++-- src/components/AddToDoForm.jsx | 2 ++ tsconfig.json | 11 +++++++++++ 4 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index 8ddffb5c..ba386a4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,13 +18,14 @@ "zustand": "^5.0.1" }, "devDependencies": { - "@types/react": "^18.2.15", - "@types/react-dom": "^18.2.7", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@vitejs/plugin-react": "^4.0.3", "eslint": "^8.45.0", "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", + "typescript": "^5.7.2", "vite": "^4.4.5" } }, @@ -654,28 +655,26 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.2.37", + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.15", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "dev": true, "license": "MIT", "dependencies": { "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.6", - "devOptional": true, - "license": "MIT" - }, "node_modules/@types/stylis": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", @@ -3198,6 +3197,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "dev": true, diff --git a/package.json b/package.json index a53bf1ed..11dc33d6 100644 --- a/package.json +++ b/package.json @@ -20,13 +20,14 @@ "zustand": "^5.0.1" }, "devDependencies": { - "@types/react": "^18.2.15", - "@types/react-dom": "^18.2.7", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@vitejs/plugin-react": "^4.0.3", "eslint": "^8.45.0", "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", + "typescript": "^5.7.2", "vite": "^4.4.5" } } diff --git a/src/components/AddToDoForm.jsx b/src/components/AddToDoForm.jsx index e2f55328..e3dd1c2c 100644 --- a/src/components/AddToDoForm.jsx +++ b/src/components/AddToDoForm.jsx @@ -1,3 +1,5 @@ +// AddToDoForm + import { useState } from "react"; import useTodoStore from "../stores/store"; import styled from "styled-components"; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..bfc1e764 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "strict": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "target": "ES6", + "module": "ESNext", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + } +} \ No newline at end of file From b075ab888f30c3a96977e1f353bcd45ab3f03b1a Mon Sep 17 00:00:00 2001 From: Jonash189 Date: Thu, 28 Nov 2024 16:29:41 +0100 Subject: [PATCH 07/15] Adding string,boolean and number as type to my function conter. --- src/Page/MyToDoListPage.jsx | 4 +++- src/components/Counter.tsx | 12 ++++++++++++ src/components/counter.jsx | 12 ------------ tsconfig.json | 28 +++++++++++++++++++++++----- 4 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 src/components/Counter.tsx delete mode 100644 src/components/counter.jsx diff --git a/src/Page/MyToDoListPage.jsx b/src/Page/MyToDoListPage.jsx index 693b14bf..2acc0936 100644 --- a/src/Page/MyToDoListPage.jsx +++ b/src/Page/MyToDoListPage.jsx @@ -1,6 +1,8 @@ +// MyToDoList + import ToDoList from '../components/ToDoList'; import AddToDoForm from '../components/AddToDoForm'; -import Counter from '../components/Counter'; +import Counter from "../components/Counter"; import styled from "styled-components"; const StyledContainer = styled.div` diff --git a/src/components/Counter.tsx b/src/components/Counter.tsx new file mode 100644 index 00000000..436fe0b4 --- /dev/null +++ b/src/components/Counter.tsx @@ -0,0 +1,12 @@ +// counter.tsx + +import useTodoStore from "../stores/store"; + +const Counter = () => { + const todos: { id: string; text: string; completed: boolean }[] = useTodoStore((state) => state.todos); + const uncompletedCount: number = todos.filter((todo) => !todo.completed).length; + + return

Uncompleted tasks: {uncompletedCount}

; +} + +export default Counter; diff --git a/src/components/counter.jsx b/src/components/counter.jsx deleted file mode 100644 index a39a37aa..00000000 --- a/src/components/counter.jsx +++ /dev/null @@ -1,12 +0,0 @@ -// counter.jsx - -import useTodoStore from "../stores/store"; - -const Counter = () => { - const todos = useTodoStore((state) => state.todos); - const uncompletedCount = todos.filter((todo) => !todo.completed).length; - - return

Uncompleted tasks: {uncompletedCount}

; -} - -export default Counter; diff --git a/tsconfig.json b/tsconfig.json index bfc1e764..5b9fbb7a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,29 @@ { "compilerOptions": { - "strict": true, - "jsx": "react-jsx", - "moduleResolution": "node", "target": "ES6", "module": "ESNext", + "jsx": "react-jsx", + "moduleResolution": "node", + "strict": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "esModuleInterop": true, "allowSyntheticDefaultImports": true, - "esModuleInterop": true - } + "baseUrl": ".", + "paths": { + "@components/*": [ + "src/components/*" + ], + "@stores/*": [ + "src/stores/*" + ] + } + }, + "include": [ + "src" + ], + "exclude": [ + "node_modules", + "dist" + ] } \ No newline at end of file From 595f71f5098a58948c0d935edaaee0b9970462bc Mon Sep 17 00:00:00 2001 From: Jonash189 Date: Thu, 28 Nov 2024 16:46:29 +0100 Subject: [PATCH 08/15] Added TypeScript to ToDoList components. Fixed styled-components prop issue. --- src/Page/MyToDoListPage.jsx | 2 +- src/components/{ToDoList.jsx => ToDoList.tsx} | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) rename src/components/{ToDoList.jsx => ToDoList.tsx} (78%) diff --git a/src/Page/MyToDoListPage.jsx b/src/Page/MyToDoListPage.jsx index 2acc0936..8789fc1a 100644 --- a/src/Page/MyToDoListPage.jsx +++ b/src/Page/MyToDoListPage.jsx @@ -34,7 +34,7 @@ const StyledContainer = styled.div` const StyledToDoList = styled.div` width: 100%; -height: 100 %; +height: 100%; overflow - y: auto; padding: 10px; `; diff --git a/src/components/ToDoList.jsx b/src/components/ToDoList.tsx similarity index 78% rename from src/components/ToDoList.jsx rename to src/components/ToDoList.tsx index 6948336c..61ec234f 100644 --- a/src/components/ToDoList.jsx +++ b/src/components/ToDoList.tsx @@ -3,6 +3,12 @@ import useTodoStore from "../stores/store"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faTrash } from "@fortawesome/free-solid-svg-icons"; +type Todo = { + id: string; + text: string; + completed: boolean; +}; + const List = styled.ul` list-style: none; @@ -23,7 +29,7 @@ const ListItem = styled.li` box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.1); `; -const Label = styled.label` +const Label = styled.label<{ $completed: boolean }>` display: flex; align-items: center; gap: 10px; @@ -47,16 +53,18 @@ const RemoveIcon = styled(FontAwesomeIcon)` } `; + + const ToDoList = () => { - const todos = useTodoStore((state) => state.todos); - const toggleTodo = useTodoStore((state) => state.toggleTodo); - const removeTodo = useTodoStore((state) => state.removeTodo); + const todos: Todo[] = useTodoStore((state) => state.todos); + const toggleTodo: (id: string) => void = useTodoStore((state) => state.toggleTodo); + const removeTodo: (id: string) => void = useTodoStore((state) => state.removeTodo); return ( {todos.map((todo) => ( -