├── src
├── index.js
├── utils.js
├── index.html
├── interactive.js
├── style.css
└── addRemove.js
├── .gitignore
├── dist
├── main.js.LICENSE.txt
└── index.html
├── .hintrc
├── .eslintrc.json
├── webpack.config.js
├── .stylelintrc.json
├── LICENSE
├── package.json
├── .github
└── workflows
│ └── linters.yml
└── README.md
/src/index.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/dist/main.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * Lodash
4 | * Copyright OpenJS Foundation and other contributors
5 | * Released under MIT license
6 | * Based on Underscore.js 1.8.3
7 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
8 | */
9 |
--------------------------------------------------------------------------------
/.hintrc:
--------------------------------------------------------------------------------
1 | {
2 | "connector": {
3 | "name": "local",
4 | "options": {
5 | "pattern": ["**", "!.git/**", "!node_modules/**"]
6 | }
7 | },
8 | "extends": ["development"],
9 | "formatters": ["stylish"],
10 | "hints": [
11 | "button-type",
12 | "disown-opener",
13 | "html-checker",
14 | "meta-charset-utf-8",
15 | "meta-viewport",
16 | "no-inline-styles:error"
17 | ]
18 | }
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true,
5 | "jest": true
6 | },
7 | "parser": "babel-eslint",
8 | "parserOptions": {
9 | "ecmaVersion": 2018,
10 | "sourceType": "module"
11 | },
12 | "extends": ["airbnb-base"],
13 | "rules": {
14 | "no-shadow": "off",
15 | "no-param-reassign": "off",
16 | "eol-last": "off",
17 | "import/extensions": [ 1, {
18 | "js": "always", "json": "always"
19 | }]
20 | },
21 | "ignorePatterns": [
22 | "dist/",
23 | "build/"
24 | ]
25 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 |
4 | module.exports = {
5 | mode: 'development',
6 | entry: './src/addRemove.js',
7 | devServer: {
8 | static: './dist',
9 | },
10 | plugins: [
11 | new HtmlWebpackPlugin({
12 | template: './src/index.html',
13 | }),
14 | ],
15 | output: {
16 | filename: 'main.js',
17 | path: path.resolve(__dirname, 'dist'),
18 | },
19 |
20 | module: {
21 | rules: [
22 | {
23 | test: /\.css$/i,
24 | use: ['style-loader', 'css-loader'],
25 | },
26 | ],
27 | },
28 | };
--------------------------------------------------------------------------------
/.stylelintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["stylelint-config-standard"],
3 | "plugins": ["stylelint-scss", "stylelint-csstree-validator"],
4 | "rules": {
5 | "at-rule-no-unknown": [
6 | true,
7 | {
8 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"]
9 | }
10 | ],
11 | "scss/at-rule-no-unknown": [
12 | true,
13 | {
14 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"]
15 | }
16 | ],
17 | "csstree/validator": true
18 | },
19 | "ignoreFiles": ["build/**", "dist/**", "**/reset*.css", "**/bootstrap*.css", "**/*.js", "**/*.jsx"]
20 | }
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | To Do List
8 |
9 |
10 | Today's To Do
11 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | To Do List
8 |
9 |
10 | Today's To Do
11 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/interactive.js:
--------------------------------------------------------------------------------
1 | const tasks = JSON.parse(localStorage.getItem('tasks')) || [];
2 |
3 | export function updateTaskStatus(task, status) {
4 | task.completed = status;
5 | localStorage.setItem('tasks', JSON.stringify(tasks));
6 | }
7 |
8 | export function checkAllCompleted() {
9 | const anyCompleted = tasks.some((task) => task.completed);
10 | const clearAllButton = document.getElementById('clear-all');
11 | clearAllButton.disabled = !anyCompleted;
12 | clearAllButton.addEventListener('click', () => {
13 | const completedTasks = tasks.filter((task) => task.completed);
14 | const remainingTasks = tasks.filter((task) => !task.completed);
15 | localStorage.setItem('tasks', JSON.stringify(remainingTasks));
16 | completedTasks.forEach((task) => {
17 | const index = tasks.indexOf(task);
18 | tasks.splice(index, 1);
19 | });
20 | checkAllCompleted();
21 | window.location.reload();
22 | });
23 | }
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 osugo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "to-do-list",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": "true",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "watch": "webpack --watch",
9 | "start": "webpack serve --open",
10 | "build": "webpack"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/0sugo/to-do-list.git"
15 | },
16 | "keywords": [],
17 | "author": "",
18 | "license": "ISC",
19 | "bugs": {
20 | "url": "https://github.com/0sugo/to-do-list/issues"
21 | },
22 | "homepage": "https://github.com/0sugo/to-do-list#readme",
23 | "devDependencies": {
24 | "babel-eslint": "^10.1.0",
25 | "css-loader": "^6.7.3",
26 | "eslint": "^7.32.0",
27 | "eslint-config-airbnb-base": "^14.2.1",
28 | "eslint-plugin-import": "^2.27.5",
29 | "hint": "^7.1.7",
30 | "html-webpack-plugin": "^5.5.0",
31 | "style-loader": "^3.3.2",
32 | "stylelint": "^13.13.1",
33 | "stylelint-config-standard": "^21.0.0",
34 | "stylelint-csstree-validator": "^1.9.0",
35 | "stylelint-scss": "^3.21.0",
36 | "webpack": "^5.76.3",
37 | "webpack-cli": "^5.0.1",
38 | "webpack-dev-server": "^4.13.1"
39 | },
40 | "dependencies": {
41 | "lodash": "^4.17.21"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: sans-serif;
3 | margin: 0.5rem auto;
4 | padding: 0;
5 | }
6 |
7 | h1 {
8 | font-size: 3rem;
9 | margin-top: 2rem;
10 | margin-left: 2rem;
11 | }
12 |
13 | p {
14 | margin: 2rem;
15 | font-size: 20px;
16 | }
17 |
18 | #task-list {
19 | margin: 0.5rem auto;
20 | width: 95%;
21 | }
22 |
23 | ul {
24 | list-style-type: none;
25 | margin: 0;
26 | padding: 0;
27 | }
28 |
29 | li {
30 | display: flex;
31 | align-items: center;
32 | background-color: #f5f5f5;
33 | border: 1px solid #ddd;
34 | padding: 1rem;
35 | margin-bottom: 1rem;
36 | }
37 |
38 | input[type="checkbox"] {
39 | margin-right: 1rem;
40 | }
41 |
42 | .completed {
43 | text-decoration: line-through;
44 | }
45 |
46 | .completed2 {
47 | text-decoration: unset;
48 | }
49 |
50 | #clear-all {
51 | text-align: center;
52 | display: block;
53 | font-size: 1.2rem;
54 | padding: 0.5rem 1rem;
55 | background-color: #f5f5f5;
56 | border: 1px solid #ddd;
57 | cursor: pointer;
58 | width: 95%;
59 | margin: 0.5rem auto;
60 | }
61 |
62 | #clear-all:hover {
63 | background-color: #ddd;
64 | }
65 |
66 | #clear-all:disabled {
67 | cursor: default;
68 | background-color: #ddd;
69 | color: #999;
70 | border-color: #999;
71 | }
72 |
73 | #edit {
74 | position: relative;
75 | }
76 |
77 | #delete {
78 | position: relative;
79 | }
80 |
81 | #identifier {
82 | display: flex;
83 | justify-content: space-between;
84 | }
85 |
86 | form {
87 | display: flex;
88 | justify-content: center;
89 | }
90 |
91 | #savg:hover {
92 | cursor: move;
93 | }
94 |
--------------------------------------------------------------------------------
/.github/workflows/linters.yml:
--------------------------------------------------------------------------------
1 | name: Linters
2 |
3 | on: pull_request
4 |
5 | env:
6 | FORCE_COLOR: 1
7 |
8 | jobs:
9 | lighthouse:
10 | name: Lighthouse
11 | runs-on: ubuntu-22.04
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: actions/setup-node@v1
15 | with:
16 | node-version: "16.x"
17 | - name: Setup Lighthouse
18 | run: npm install -g @lhci/cli@0.7.x
19 | - name: Lighthouse Report
20 | run: lhci autorun --upload.target=temporary-public-storage --collect.staticDistDir=.
21 | webhint:
22 | name: Webhint
23 | runs-on: ubuntu-22.04
24 | steps:
25 | - uses: actions/checkout@v2
26 | - uses: actions/setup-node@v1
27 | with:
28 | node-version: "16.x"
29 | - name: Setup Webhint
30 | run: |
31 | npm install --save-dev hint@7.x
32 | [ -f .hintrc ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.hintrc
33 | - name: Webhint Report
34 | run: npx hint .
35 | stylelint:
36 | name: Stylelint
37 | runs-on: ubuntu-22.04
38 | steps:
39 | - uses: actions/checkout@v2
40 | - uses: actions/setup-node@v1
41 | with:
42 | node-version: "18.x"
43 | - name: Setup Stylelint
44 | run: |
45 | npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x
46 | [ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.stylelintrc.json
47 | - name: Stylelint Report
48 | run: npx stylelint "**/*.{css,scss}"
49 | eslint:
50 | name: ESLint
51 | runs-on: ubuntu-22.04
52 | steps:
53 | - uses: actions/checkout@v2
54 | - uses: actions/setup-node@v1
55 | with:
56 | node-version: "18.x"
57 | - name: Setup ESLint
58 | run: |
59 | npm install --save-dev eslint@7.x eslint-config-airbnb-base@14.x eslint-plugin-import@2.x babel-eslint@10.x
60 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.eslintrc.json
61 | - name: ESLint Report
62 | run: npx eslint .
63 | nodechecker:
64 | name: node_modules checker
65 | runs-on: ubuntu-22.04
66 | steps:
67 | - uses: actions/checkout@v2
68 | - name: Check node_modules existence
69 | run: |
70 | if [ -d "node_modules/" ]; then echo -e "\e[1;31mThe node_modules/ folder was pushed to the repo. Please remove it from the GitHub repository and try again."; echo -e "\e[1;32mYou can set up a .gitignore file with this folder included on it to prevent this from happening in the future." && exit 1; fi
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # 📗 Table of Contents
5 |
6 | - [📗 Table of Contents](#-table-of-contents)
7 | - [📖 To Do List ](#-to-do-list-)
8 | - [🛠 Built With ](#-built-with-)
9 | - [Tech Stack ](#tech-stack-)
10 | - [Key Features ](#key-features-)
11 | - [🚀 Live Demo ](#-live-demo-)
12 | - [💻 Getting Started ](#-getting-started-)
13 | - [Prerequisites](#prerequisites)
14 | - [Setup](#setup)
15 | - [Install](#install)
16 | - [Usage](#usage)
17 | - [Run tests](#run-tests)
18 | - [Deployment](#deployment)
19 | - [👥 Authors ](#-authors-)
20 | - [🔭 Future Features ](#-future-features-)
21 | - [🤝 Contributing ](#-contributing-)
22 | - [⭐️ Show your support ](#️-show-your-support-)
23 | - [🙏 Acknowledgments ](#-acknowledgments-)
24 | - [📝 LICENSE ](#-license-)
25 |
26 |
27 |
28 | # 📖 To Do List
29 |
30 |
31 | **To Do List** is an application that shows things I intended to do in a day keeping track with a tick for those I have completed.
32 |
33 | ## 🛠 Built With
34 |
35 | ### Tech Stack
36 |
37 |
38 | Client
39 |
43 |
44 |
45 |
46 | Server
47 |
50 |
51 |
52 |
53 | Database
54 |
57 |
58 |
59 |
60 |
61 | ### Key Features
62 |
63 | - **To-do-list**
64 | - **Setup with Webpack**
65 | - **CSS loader Webpack**
66 | - **HTML Webpack Plugin**
67 | - **Source files in src(Folder)**
68 | - **dist (folder)**
69 |
70 |
71 |
72 |
73 | ## 🚀 Live Demo
74 |
75 |
76 | - [Live Demo Link](https://0sugo.github.io/to-do-list/dist/)
77 |
78 |
79 |
80 |
81 | ## 💻 Getting Started
82 |
83 |
84 | To get a local copy up and running, follow these steps.
85 |
86 | ### Prerequisites
87 |
88 | In order to run this project you need:
89 |
90 | - Modern chrome Browser
91 | - visual studio code
92 |
93 | ### Setup
94 |
95 | - Clone this repository to your desired folder with the following commnd
96 | ```
97 | git clone https://github.com/0sugo/to-do-list.git
98 | ```
99 |
100 |
101 | ### Install
102 |
103 | - run ```npm i``` to install all dependencies
104 | - run ```npm run build``` to bundle the project with webpack, and
105 |
106 |
107 | ### Usage
108 |
109 | - To run the project, execute the following command:
110 | -- run ```npm start``` to launch the application
111 |
112 | ### Run tests
113 |
114 | - To run tests, run the following command:
115 | - ```npm run tests```
116 |
117 | ### Deployment
118 |
119 | - You can deploy this project using:
120 | - Type cd ``` To-Do-List ```
121 | - open index.html file in the browser
122 |
123 |
124 |
125 | ## 👥 Authors
126 |
127 | 👤 **JOSECK OSUGO**
128 |
129 | - GitHub: [0sugo](https://github.com/0sugo)
130 | - Twitter: [@0sugo5](https://twitter.com/osugo5)
131 | - LinkedIn: [Joseck Osugo](https://www.linkedin.com/in/joseck-osugo-873b0618a/)
132 |
133 |
134 |
135 |
136 |
137 | ## 🔭 Future Features
138 |
139 | - [ ] **React**
140 | - [ ] **Ruby**
141 | - [ ] **Java-Script**
142 |
143 |
144 |
145 |
146 | ## 🤝 Contributing
147 |
148 | Contributions, issues, and feature requests are welcome!
149 |
150 | Feel free to check the [issues page]([../../issues/](https://github.com/0sugo/to-do-list/issues)).
151 |
152 |
153 |
154 |
155 | ## ⭐️ Show your support
156 |
157 |
158 | - If you like this project please give it a STAR⭐️
159 |
160 |
161 |
162 |
163 | ## 🙏 Acknowledgments
164 |
165 | - I would like to thank following
166 | - MicroVerse
167 | - web.archive.org.
168 |
169 |
170 |
171 | ## 📝 LICENSE
172 |
173 | This project is [MIT](./LICENSE) licensed.
174 |
175 | (back to top)
176 |
177 |
--------------------------------------------------------------------------------
/src/addRemove.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import './style.css';
3 | import { updateTaskStatus, checkAllCompleted } from './interactive.js';
4 |
5 | const tasks = JSON.parse(localStorage.getItem('tasks')) || [];
6 |
7 | const taskList = document.getElementById('task-list');
8 |
9 | function component() {
10 | const element = document.createElement('div');
11 |
12 | // lodash imported by script
13 | element.innerHTML = _.join(['', ''], ' ');
14 | return element;
15 | }
16 |
17 | document.body.appendChild(component());
18 |
19 | // able and disable button
20 |
21 | // render infor to html
22 | function renderTaskList() {
23 | taskList.innerHTML = '';
24 | // const task = JSON.parse(localStorage.getItem('tasks')) || [];
25 |
26 | tasks.forEach((task, index) => {
27 | task.index = index;
28 | const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
29 | const svgDelete = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
30 | const listItem = document.createElement('li');
31 | listItem.id = 'identifier';
32 |
33 | // function to re assign indexes
34 | function assignIndexesToLocalTasks() {
35 | const tasks = JSON.parse(localStorage.getItem('tasks'));
36 |
37 | tasks.forEach((task, index) => {
38 | task.index = index;
39 | });
40 | localStorage.setItem('tasks', JSON.stringify(tasks));
41 | }
42 |
43 | // add a draggable attribute to the li element
44 | listItem.draggable = true;
45 |
46 | // set up the dragstart event listener to store the task index in the dataTransfer object
47 | listItem.addEventListener('dragstart', (event) => {
48 | event.dataTransfer.setData('text/plain', index);
49 | event.dataTransfer.effectAllowed = 'move';
50 | });
51 |
52 | // set up the dragover event listener to allow the li element to be dropped on top of it
53 | listItem.addEventListener('dragover', (event) => {
54 | event.preventDefault();
55 | event.dataTransfer.dropEffect = 'move';
56 | });
57 |
58 | // set up the drop event listener to swap the positions of the dragged task and the dropped task
59 | listItem.addEventListener('drop', (event) => {
60 | event.preventDefault();
61 | const sourceIndex = event.dataTransfer.getData('text/plain');
62 | if (sourceIndex !== index) {
63 | const sourceTask = tasks[sourceIndex];
64 | const targetTask = tasks[index];
65 | tasks[sourceIndex] = targetTask;
66 | tasks[index] = sourceTask;
67 | localStorage.setItem('tasks', JSON.stringify(tasks));
68 | assignIndexesToLocalTasks();
69 | renderTaskList();
70 | }
71 | });
72 |
73 | // update the indexes of the list items
74 | const listItems = document.querySelectorAll('.task');
75 | listItems.forEach((listItem) => {
76 | // retrieve the index from the list item's id attribute
77 | const taskIndex = parseInt(listItem.id.split('-')[1], 10);
78 | listItem.dataset.index = taskIndex;
79 | renderTaskList();
80 | });
81 |
82 | const checkbox = document.createElement('input');
83 | checkbox.type = 'checkbox';
84 | checkbox.checked = task.completed;
85 | checkbox.addEventListener('change', (event) => {
86 | updateTaskStatus(task, event.target.checked);
87 | checkAllCompleted();
88 | window.location.reload();
89 | localStorage.setItem('tasks', JSON.stringify(tasks));
90 | if (event.target.checked) {
91 | listItem.classList.add('completed');
92 | checkAllCompleted();
93 | // listItem.style.textDecoration = 'line-through';
94 | } else {
95 | listItem.classList.remove('completed');
96 | // listItem.style.textDecoration = 'unset';
97 | }
98 | });
99 | listItem.appendChild(checkbox);
100 |
101 | const description = document.createElement('span');
102 | description.innerText = task.description;
103 | if (task.completed) {
104 | description.classList.add('completed');
105 | }
106 | listItem.appendChild(description);
107 |
108 | const editButton = document.createElement('button');
109 | editButton.id = 'edit';
110 |
111 | listItem.appendChild(editButton);
112 |
113 | const editInput = document.createElement('input');
114 | editInput.type = 'text';
115 | editInput.value = task.description;
116 | editInput.style.display = 'none';
117 | listItem.appendChild(editInput);
118 |
119 | listItem.addEventListener('click', (event) => {
120 | if (event.target.id === 'edit') {
121 | description.style.display = 'none';
122 | editInput.style.display = 'inline-block';
123 | editInput.focus();
124 | listItem.style.backgroundColor = '#326789';
125 | svg.style.display = 'none';
126 | }
127 | });
128 |
129 | editInput.addEventListener('keyup', (event) => {
130 | if (event.key === 'Enter') {
131 | const newDescription = editInput.value.trim();
132 | if (newDescription !== '') {
133 | task.description = newDescription;
134 | description.innerText = newDescription;
135 | description.style.display = 'inline-block';
136 | editInput.style.display = 'none';
137 | svgDelete.style.display = 'none';
138 | listItem.style.backgroundColor = 'unset';
139 | svg.style.display = 'unset';
140 | localStorage.setItem('tasks', JSON.stringify(tasks));
141 | }
142 | }
143 | });
144 |
145 | listItem.appendChild(editInput);
146 |
147 | // create a new SVG element
148 | svg.id = 'savg';
149 | svg.setAttribute('style', 'cursor: default;'); // set default cursor
150 | svg.addEventListener('mouseover', () => {
151 | svg.style.cursor = 'move'; // set move cursor on hover
152 | });
153 | svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
154 | svg.setAttribute('fill', 'none');
155 | svg.setAttribute('viewBox', '0 0 24 24');
156 | svg.setAttribute('stroke-width', '1.5');
157 | svg.setAttribute('stroke', 'currentColor');
158 | svg.setAttribute('class', 'w-6 h-6');
159 | svg.setAttribute('width', '18');
160 | svg.setAttribute('height', '32');
161 |
162 | // create a new path element
163 | const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
164 | path.setAttribute('stroke-linecap', 'round');
165 | path.setAttribute('stroke-linejoin', 'round');
166 | path.setAttribute('d', 'M12 6.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 12.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 18.75a.75.75 0 110-1.5.75.75 0 010 1.5z');
167 |
168 | // add the path element to the SVG element
169 | svg.appendChild(path);
170 | listItem.appendChild(svg);
171 |
172 | // add event listener to SVG element
173 | description.addEventListener('click', () => {
174 | editButton.click();
175 | svgDelete.style.display = 'block';
176 | });
177 |
178 | // add event listener to edit button
179 | editButton.addEventListener('click', () => {
180 | description.style.display = 'none';
181 | editInput.style.display = 'inline-block';
182 | editInput.focus();
183 | });
184 |
185 | svgDelete.style.display = 'none';
186 | svgDelete.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
187 | svgDelete.setAttribute('fill', 'none');
188 | svgDelete.setAttribute('viewBox', '0 0 24 24');
189 | svgDelete.setAttribute('stroke-width', '1.5');
190 | svgDelete.setAttribute('stroke', 'currentColor');
191 | svgDelete.setAttribute('class', 'w-6 h-6 svgDelete'); // add a new class name "svgDelete"
192 | svgDelete.setAttribute('width', '18');
193 | svgDelete.setAttribute('height', '32');
194 |
195 | const pathDelete = document.createElementNS('http://www.w3.org/2000/svg', 'path');
196 | pathDelete.setAttribute('stroke-linecap', 'round');
197 | pathDelete.setAttribute('stroke-linejoin', 'round');
198 | pathDelete.setAttribute('d', 'M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0');
199 | svgDelete.appendChild(pathDelete);
200 | listItem.appendChild(svgDelete);
201 |
202 | svgDelete.addEventListener('click', () => {
203 | const index = tasks.findIndex((t) => t.index === task.index);
204 | if (index > -1) {
205 | tasks.splice(index, 1);
206 | renderTaskList();
207 | localStorage.setItem('tasks', JSON.stringify(tasks));
208 | listItem.remove();
209 | }
210 | });
211 |
212 | taskList.appendChild(listItem);
213 | });
214 | }
215 | window.onload = function onload() {
216 | renderTaskList();
217 | checkAllCompleted();
218 | };
219 |
220 | renderTaskList();
221 | checkAllCompleted();
222 |
223 | const myForm = document.getElementById('myform');
224 | myForm.addEventListener('submit', (event) => {
225 | event.preventDefault();
226 |
227 | const individualTask = document.getElementById('individualTask').value;
228 | if (individualTask.trim() !== '') {
229 | const newObj = {
230 | description: individualTask,
231 | completed: false,
232 | index: tasks.length,
233 | };
234 | tasks.push(newObj);
235 | localStorage.setItem('tasks', JSON.stringify(tasks));
236 |
237 | // clear input field
238 | document.getElementById('individualTask').value = '';
239 |
240 | renderTaskList();
241 | checkAllCompleted();
242 | }
243 | });
244 |
--------------------------------------------------------------------------------