├── .eslintrc.json
├── .github
└── workflows
│ └── linters.yml
├── .gitignore
├── .hintrc
├── .stylelintrc.json
├── README.md
├── dist
├── index.html
└── main.js
├── package-lock.json
├── package.json
├── src
├── index.html
├── index.js
├── modules
│ ├── Task.js
│ └── completed.js
└── style.css
└── webpack.config.js
/.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": [
18 | 1,
19 | {
20 | "js": "always",
21 | "json": "always"
22 | }
23 | ]
24 | },
25 | "ignorePatterns": ["dist/", "build/"]
26 | }
27 |
--------------------------------------------------------------------------------
/.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-18.04
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: actions/setup-node@v1
15 | with:
16 | node-version: '12.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-18.04
24 | steps:
25 | - uses: actions/checkout@v2
26 | - uses: actions/setup-node@v1
27 | with:
28 | node-version: '12.x'
29 | - name: Setup Webhint
30 | run: |
31 | npm install --save-dev hint@6.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-18.04
38 | steps:
39 | - uses: actions/checkout@v2
40 | - uses: actions/setup-node@v1
41 | with:
42 | node-version: '12.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-18.04
52 | steps:
53 | - uses: actions/checkout@v2
54 | - uses: actions/setup-node@v1
55 | with:
56 | node-version: '12.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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.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 | }
19 |
--------------------------------------------------------------------------------
/.stylelintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["stylelint-config-standard"],
3 | "plugins": ["stylelint-scss", "stylelint-csstree-validator"],
4 | "rules": {
5 | "at-rule-no-unknown": null,
6 | "scss/at-rule-no-unknown": true,
7 | "csstree/validator": true
8 | },
9 | "ignoreFiles": [
10 | "build/**",
11 | "dist/**",
12 | "**/reset*.css",
13 | "**/bootstrap*.css",
14 | "**/*.js",
15 | "**/*.jsx"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | # To Do List
3 |
4 | Application that record the tasks to remind you and got many features that you might need.
5 |
6 | ## This is an image for it
7 |
8 | ## Live Demo
9 | [Live Demo Here](https://omar25ahmed.github.io/ToDo-List/)
10 |
11 |
12 |
13 |
14 | ## Built With
15 |
16 | - HTML
17 | - CSS
18 | - Markdown
19 | - JavaScript
20 |
21 | ## Prerequisites
22 |
23 | - text-editor
24 | - git
25 | - github
26 |
27 | ## Getting Started
28 |
29 | **To Create A Portfolio from this Repository feel free to contact me.**
30 |
31 | **To get a local copy up and running follow these simple steps.**
32 | - you can clone this repo by typing `git clone git@github.com:omar25ahmed/Omar-Ragheb-ToDo-List`.
33 | - type `cd ToDo List` to access the project on terminal.
34 |
35 | ## Authors
36 |
37 | 👤 **Omar Ragheb**
38 |
39 | - - GitHub: [@omar25ahmed](https://github.com/omar25ahmed)
40 |
41 |
42 | ## 🤝 Contributing
43 |
44 | Contributions, issues, and feature requests are welcome!
45 |
46 | Feel free to check the [issues page](https://github.com/omar25ahmed/Portfolio-setup-and-mobile-version-skeleton/issues).
47 |
48 | ## Show your support
49 |
50 | Give a ⭐️ if you like this project!
51 |
52 | ## Acknowledgments
53 |
54 | - Cindy Shin's design
55 | - SciComm [Link](https://www.scicommcon.org/)
56 | - Aspen Global Congress on Scientific Thinking & Action [Link](https://www.aspeninstitute.org/programs/science-society/global-science-congress/)
57 | - Microverse Team
58 |
59 | ## 📝 License
60 |
61 | This project is [MIT](./MIT.md) licensed.
62 |
63 | - GitHub: [@omar25ahmed](https://github.com/omar25ahmed)
64 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | To Do List
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
24 |
26 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/dist/main.js:
--------------------------------------------------------------------------------
1 | /******/ (() => { // webpackBootstrap
2 | /******/ "use strict";
3 | /******/ var __webpack_modules__ = ([
4 | /* 0 */,
5 | /* 1 */
6 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
7 |
8 | __webpack_require__.r(__webpack_exports__);
9 | /* harmony export */ __webpack_require__.d(__webpack_exports__, {
10 | /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
11 | /* harmony export */ });
12 | /* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
13 | /* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);
14 | /* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
15 | /* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);
16 | /* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
17 | /* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);
18 | /* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5);
19 | /* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);
20 | /* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6);
21 | /* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);
22 | /* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7);
23 | /* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);
24 | /* harmony import */ var _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8);
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | var options = {};
37 |
38 | options.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());
39 | options.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());
40 |
41 | options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, "head");
42 |
43 | options.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());
44 | options.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());
45 |
46 | var update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__["default"], options);
47 |
48 |
49 |
50 |
51 | /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__["default"] && _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__["default"].locals ? _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__["default"].locals : undefined);
52 |
53 |
54 | /***/ }),
55 | /* 2 */
56 | /***/ ((module) => {
57 |
58 |
59 |
60 | var stylesInDOM = [];
61 |
62 | function getIndexByIdentifier(identifier) {
63 | var result = -1;
64 |
65 | for (var i = 0; i < stylesInDOM.length; i++) {
66 | if (stylesInDOM[i].identifier === identifier) {
67 | result = i;
68 | break;
69 | }
70 | }
71 |
72 | return result;
73 | }
74 |
75 | function modulesToDom(list, options) {
76 | var idCountMap = {};
77 | var identifiers = [];
78 |
79 | for (var i = 0; i < list.length; i++) {
80 | var item = list[i];
81 | var id = options.base ? item[0] + options.base : item[0];
82 | var count = idCountMap[id] || 0;
83 | var identifier = "".concat(id, " ").concat(count);
84 | idCountMap[id] = count + 1;
85 | var indexByIdentifier = getIndexByIdentifier(identifier);
86 | var obj = {
87 | css: item[1],
88 | media: item[2],
89 | sourceMap: item[3],
90 | supports: item[4],
91 | layer: item[5]
92 | };
93 |
94 | if (indexByIdentifier !== -1) {
95 | stylesInDOM[indexByIdentifier].references++;
96 | stylesInDOM[indexByIdentifier].updater(obj);
97 | } else {
98 | var updater = addElementStyle(obj, options);
99 | options.byIndex = i;
100 | stylesInDOM.splice(i, 0, {
101 | identifier: identifier,
102 | updater: updater,
103 | references: 1
104 | });
105 | }
106 |
107 | identifiers.push(identifier);
108 | }
109 |
110 | return identifiers;
111 | }
112 |
113 | function addElementStyle(obj, options) {
114 | var api = options.domAPI(options);
115 | api.update(obj);
116 |
117 | var updater = function updater(newObj) {
118 | if (newObj) {
119 | if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {
120 | return;
121 | }
122 |
123 | api.update(obj = newObj);
124 | } else {
125 | api.remove();
126 | }
127 | };
128 |
129 | return updater;
130 | }
131 |
132 | module.exports = function (list, options) {
133 | options = options || {};
134 | list = list || [];
135 | var lastIdentifiers = modulesToDom(list, options);
136 | return function update(newList) {
137 | newList = newList || [];
138 |
139 | for (var i = 0; i < lastIdentifiers.length; i++) {
140 | var identifier = lastIdentifiers[i];
141 | var index = getIndexByIdentifier(identifier);
142 | stylesInDOM[index].references--;
143 | }
144 |
145 | var newLastIdentifiers = modulesToDom(newList, options);
146 |
147 | for (var _i = 0; _i < lastIdentifiers.length; _i++) {
148 | var _identifier = lastIdentifiers[_i];
149 |
150 | var _index = getIndexByIdentifier(_identifier);
151 |
152 | if (stylesInDOM[_index].references === 0) {
153 | stylesInDOM[_index].updater();
154 |
155 | stylesInDOM.splice(_index, 1);
156 | }
157 | }
158 |
159 | lastIdentifiers = newLastIdentifiers;
160 | };
161 | };
162 |
163 | /***/ }),
164 | /* 3 */
165 | /***/ ((module) => {
166 |
167 |
168 |
169 | /* istanbul ignore next */
170 | function apply(styleElement, options, obj) {
171 | var css = "";
172 |
173 | if (obj.supports) {
174 | css += "@supports (".concat(obj.supports, ") {");
175 | }
176 |
177 | if (obj.media) {
178 | css += "@media ".concat(obj.media, " {");
179 | }
180 |
181 | var needLayer = typeof obj.layer !== "undefined";
182 |
183 | if (needLayer) {
184 | css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {");
185 | }
186 |
187 | css += obj.css;
188 |
189 | if (needLayer) {
190 | css += "}";
191 | }
192 |
193 | if (obj.media) {
194 | css += "}";
195 | }
196 |
197 | if (obj.supports) {
198 | css += "}";
199 | }
200 |
201 | var sourceMap = obj.sourceMap;
202 |
203 | if (sourceMap && typeof btoa !== "undefined") {
204 | css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
205 | } // For old IE
206 |
207 | /* istanbul ignore if */
208 |
209 |
210 | options.styleTagTransform(css, styleElement, options.options);
211 | }
212 |
213 | function removeStyleElement(styleElement) {
214 | // istanbul ignore if
215 | if (styleElement.parentNode === null) {
216 | return false;
217 | }
218 |
219 | styleElement.parentNode.removeChild(styleElement);
220 | }
221 | /* istanbul ignore next */
222 |
223 |
224 | function domAPI(options) {
225 | var styleElement = options.insertStyleElement(options);
226 | return {
227 | update: function update(obj) {
228 | apply(styleElement, options, obj);
229 | },
230 | remove: function remove() {
231 | removeStyleElement(styleElement);
232 | }
233 | };
234 | }
235 |
236 | module.exports = domAPI;
237 |
238 | /***/ }),
239 | /* 4 */
240 | /***/ ((module) => {
241 |
242 |
243 |
244 | var memo = {};
245 | /* istanbul ignore next */
246 |
247 | function getTarget(target) {
248 | if (typeof memo[target] === "undefined") {
249 | var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself
250 |
251 | if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
252 | try {
253 | // This will throw an exception if access to iframe is blocked
254 | // due to cross-origin restrictions
255 | styleTarget = styleTarget.contentDocument.head;
256 | } catch (e) {
257 | // istanbul ignore next
258 | styleTarget = null;
259 | }
260 | }
261 |
262 | memo[target] = styleTarget;
263 | }
264 |
265 | return memo[target];
266 | }
267 | /* istanbul ignore next */
268 |
269 |
270 | function insertBySelector(insert, style) {
271 | var target = getTarget(insert);
272 |
273 | if (!target) {
274 | throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
275 | }
276 |
277 | target.appendChild(style);
278 | }
279 |
280 | module.exports = insertBySelector;
281 |
282 | /***/ }),
283 | /* 5 */
284 | /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
285 |
286 |
287 |
288 | /* istanbul ignore next */
289 | function setAttributesWithoutAttributes(styleElement) {
290 | var nonce = true ? __webpack_require__.nc : 0;
291 |
292 | if (nonce) {
293 | styleElement.setAttribute("nonce", nonce);
294 | }
295 | }
296 |
297 | module.exports = setAttributesWithoutAttributes;
298 |
299 | /***/ }),
300 | /* 6 */
301 | /***/ ((module) => {
302 |
303 |
304 |
305 | /* istanbul ignore next */
306 | function insertStyleElement(options) {
307 | var element = document.createElement("style");
308 | options.setAttributes(element, options.attributes);
309 | options.insert(element, options.options);
310 | return element;
311 | }
312 |
313 | module.exports = insertStyleElement;
314 |
315 | /***/ }),
316 | /* 7 */
317 | /***/ ((module) => {
318 |
319 |
320 |
321 | /* istanbul ignore next */
322 | function styleTagTransform(css, styleElement) {
323 | if (styleElement.styleSheet) {
324 | styleElement.styleSheet.cssText = css;
325 | } else {
326 | while (styleElement.firstChild) {
327 | styleElement.removeChild(styleElement.firstChild);
328 | }
329 |
330 | styleElement.appendChild(document.createTextNode(css));
331 | }
332 | }
333 |
334 | module.exports = styleTagTransform;
335 |
336 | /***/ }),
337 | /* 8 */
338 | /***/ ((module, __webpack_exports__, __webpack_require__) => {
339 |
340 | __webpack_require__.r(__webpack_exports__);
341 | /* harmony export */ __webpack_require__.d(__webpack_exports__, {
342 | /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
343 | /* harmony export */ });
344 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9);
345 | /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);
346 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
347 | /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);
348 | // Imports
349 |
350 |
351 | var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
352 | // Module
353 | ___CSS_LOADER_EXPORT___.push([module.id, "body {\n background-color: #f6f6f6;\n}\n\n.container {\n border: 1px solid;\n background-color: #fff;\n width: 50%;\n margin: auto;\n}\n\n.header {\n display: flex;\n justify-content: space-between;\n padding: 10px;\n}\n\n.header button {\n background-color: transparent;\n border: none;\n cursor: pointer;\n}\n\n.todo-add {\n display: flex;\n padding: 10px;\n}\n\n.todo-add button {\n background-color: transparent;\n border: none;\n cursor: pointer;\n}\n\n.form-field {\n font-family: inherit;\n width: 100%;\n border: 0;\n border-bottom: 2px solid #9b9b9b;\n outline: 0;\n font-size: 1.3rem;\n color: black;\n padding: 7px 0;\n background: transparent;\n transition: border-color 0.2s;\n}\n\nul {\n list-style: none;\n padding: 10px;\n}\n\n.task {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 10px;\n}\n\n.btns {\n margin-left: auto;\n display: flex;\n gap: 40px;\n}\n\n.close-button {\n transform: rotate(45deg);\n cursor: pointer;\n font-size: 30px;\n color: red;\n}\n\n.edit {\n border-color: transparent;\n height: 40px;\n}\n\n.edit:focus-visible {\n outline: green auto 1px;\n font-size: 15px;\n}\n\n.done {\n text-decoration: line-through;\n opacity: 0.5;\n}\n\n.scroll {\n background-color: transparent;\n border: none;\n cursor: pointer;\n margin-left: auto;\n}\n\n.footer {\n background-color: #f6f6f6;\n height: 50px;\n border-top: 1px solid;\n display: flex;\n justify-content: center;\n opacity: 0.5;\n}\n\n.footer button {\n background-color: transparent;\n border: none;\n cursor: pointer;\n font-size: 20px;\n}\n", ""]);
354 | // Exports
355 | /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);
356 |
357 |
358 | /***/ }),
359 | /* 9 */
360 | /***/ ((module) => {
361 |
362 |
363 |
364 | module.exports = function (i) {
365 | return i[1];
366 | };
367 |
368 | /***/ }),
369 | /* 10 */
370 | /***/ ((module) => {
371 |
372 |
373 |
374 | /*
375 | MIT License http://www.opensource.org/licenses/mit-license.php
376 | Author Tobias Koppers @sokra
377 | */
378 | module.exports = function (cssWithMappingToString) {
379 | var list = []; // return the list of modules as css string
380 |
381 | list.toString = function toString() {
382 | return this.map(function (item) {
383 | var content = "";
384 | var needLayer = typeof item[5] !== "undefined";
385 |
386 | if (item[4]) {
387 | content += "@supports (".concat(item[4], ") {");
388 | }
389 |
390 | if (item[2]) {
391 | content += "@media ".concat(item[2], " {");
392 | }
393 |
394 | if (needLayer) {
395 | content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {");
396 | }
397 |
398 | content += cssWithMappingToString(item);
399 |
400 | if (needLayer) {
401 | content += "}";
402 | }
403 |
404 | if (item[2]) {
405 | content += "}";
406 | }
407 |
408 | if (item[4]) {
409 | content += "}";
410 | }
411 |
412 | return content;
413 | }).join("");
414 | }; // import a list of modules into the list
415 |
416 |
417 | list.i = function i(modules, media, dedupe, supports, layer) {
418 | if (typeof modules === "string") {
419 | modules = [[null, modules, undefined]];
420 | }
421 |
422 | var alreadyImportedModules = {};
423 |
424 | if (dedupe) {
425 | for (var k = 0; k < this.length; k++) {
426 | var id = this[k][0];
427 |
428 | if (id != null) {
429 | alreadyImportedModules[id] = true;
430 | }
431 | }
432 | }
433 |
434 | for (var _k = 0; _k < modules.length; _k++) {
435 | var item = [].concat(modules[_k]);
436 |
437 | if (dedupe && alreadyImportedModules[item[0]]) {
438 | continue;
439 | }
440 |
441 | if (typeof layer !== "undefined") {
442 | if (typeof item[5] === "undefined") {
443 | item[5] = layer;
444 | } else {
445 | item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}");
446 | item[5] = layer;
447 | }
448 | }
449 |
450 | if (media) {
451 | if (!item[2]) {
452 | item[2] = media;
453 | } else {
454 | item[1] = "@media ".concat(item[2], " {").concat(item[1], "}");
455 | item[2] = media;
456 | }
457 | }
458 |
459 | if (supports) {
460 | if (!item[4]) {
461 | item[4] = "".concat(supports);
462 | } else {
463 | item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}");
464 | item[4] = supports;
465 | }
466 | }
467 |
468 | list.push(item);
469 | }
470 | };
471 |
472 | return list;
473 | };
474 |
475 | /***/ }),
476 | /* 11 */
477 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
478 |
479 | __webpack_require__.r(__webpack_exports__);
480 | /* harmony export */ __webpack_require__.d(__webpack_exports__, {
481 | /* harmony export */ "default": () => (/* binding */ Task)
482 | /* harmony export */ });
483 | class Task {
484 | constructor(description, index, completed = false) {
485 | this.description = description;
486 | this.completed = completed;
487 | this.index = index;
488 | }
489 | }
490 |
491 |
492 | /***/ }),
493 | /* 12 */
494 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
495 |
496 | __webpack_require__.r(__webpack_exports__);
497 | /* harmony export */ __webpack_require__.d(__webpack_exports__, {
498 | /* harmony export */ "markAsCompleted": () => (/* binding */ markAsCompleted),
499 | /* harmony export */ "clearAllCompletedTasks": () => (/* binding */ clearAllCompletedTasks)
500 | /* harmony export */ });
501 | function markAsCompleted(e, tasks) {
502 | const completedIndex = e.target.parentElement.dataset.index - 1;
503 | if (e.target.checked) {
504 | e.target.nextElementSibling.classList.add('done');
505 | tasks[completedIndex].completed = true;
506 | } else {
507 | e.target.nextElementSibling.classList.remove('done');
508 | tasks[completedIndex].completed = false;
509 | }
510 | localStorage.setItem('tasks', JSON.stringify(tasks));
511 | }
512 |
513 | function clearAllCompletedTasks(tasks) {
514 | document.querySelectorAll('.done').forEach((task) => {
515 | const deletedIndex = task.parentElement.dataset.index;
516 | const toBeUpdatedTasks = tasks.slice(deletedIndex, tasks.length);
517 | toBeUpdatedTasks.forEach((task) => {
518 | const el = document.querySelector(`[data-index="${task.index}"]`);
519 | el.dataset.index = task.index - 1;
520 | task.index -= 1;
521 | });
522 | tasks.splice(deletedIndex - 1, 1);
523 | task.parentElement.parentElement.remove();
524 | });
525 | localStorage.setItem('tasks', JSON.stringify(tasks));
526 | }
527 |
528 | /***/ })
529 | /******/ ]);
530 | /************************************************************************/
531 | /******/ // The module cache
532 | /******/ var __webpack_module_cache__ = {};
533 | /******/
534 | /******/ // The require function
535 | /******/ function __webpack_require__(moduleId) {
536 | /******/ // Check if module is in cache
537 | /******/ var cachedModule = __webpack_module_cache__[moduleId];
538 | /******/ if (cachedModule !== undefined) {
539 | /******/ return cachedModule.exports;
540 | /******/ }
541 | /******/ // Create a new module (and put it into the cache)
542 | /******/ var module = __webpack_module_cache__[moduleId] = {
543 | /******/ id: moduleId,
544 | /******/ // no module.loaded needed
545 | /******/ exports: {}
546 | /******/ };
547 | /******/
548 | /******/ // Execute the module function
549 | /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
550 | /******/
551 | /******/ // Return the exports of the module
552 | /******/ return module.exports;
553 | /******/ }
554 | /******/
555 | /************************************************************************/
556 | /******/ /* webpack/runtime/compat get default export */
557 | /******/ (() => {
558 | /******/ // getDefaultExport function for compatibility with non-harmony modules
559 | /******/ __webpack_require__.n = (module) => {
560 | /******/ var getter = module && module.__esModule ?
561 | /******/ () => (module['default']) :
562 | /******/ () => (module);
563 | /******/ __webpack_require__.d(getter, { a: getter });
564 | /******/ return getter;
565 | /******/ };
566 | /******/ })();
567 | /******/
568 | /******/ /* webpack/runtime/define property getters */
569 | /******/ (() => {
570 | /******/ // define getter functions for harmony exports
571 | /******/ __webpack_require__.d = (exports, definition) => {
572 | /******/ for(var key in definition) {
573 | /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
574 | /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
575 | /******/ }
576 | /******/ }
577 | /******/ };
578 | /******/ })();
579 | /******/
580 | /******/ /* webpack/runtime/hasOwnProperty shorthand */
581 | /******/ (() => {
582 | /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
583 | /******/ })();
584 | /******/
585 | /******/ /* webpack/runtime/make namespace object */
586 | /******/ (() => {
587 | /******/ // define __esModule on exports
588 | /******/ __webpack_require__.r = (exports) => {
589 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
590 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
591 | /******/ }
592 | /******/ Object.defineProperty(exports, '__esModule', { value: true });
593 | /******/ };
594 | /******/ })();
595 | /******/
596 | /************************************************************************/
597 | var __webpack_exports__ = {};
598 | // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
599 | (() => {
600 | __webpack_require__.r(__webpack_exports__);
601 | /* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
602 | /* harmony import */ var _modules_Task_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
603 | /* harmony import */ var _modules_completed_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(12);
604 |
605 |
606 |
607 |
608 | const form = document.querySelector('.todo-add');
609 | const input = document.querySelector('.form-field');
610 | const ul = document.getElementById('todo-list');
611 | let li;
612 | const clearBtn = document.querySelector('.todo-clear');
613 |
614 | let tasks;
615 |
616 | if (localStorage.getItem('tasks') === null) {
617 | tasks = [];
618 | } else {
619 | tasks = [];
620 | Array.from(JSON.parse(localStorage.getItem('tasks'))).forEach((task) => {
621 | tasks.push(new _modules_Task_js__WEBPACK_IMPORTED_MODULE_1__["default"](task.description, task.index, task.completed));
622 | });
623 | }
624 |
625 | function prepareEdit(task, btn) {
626 | btn.addEventListener('click', () => {
627 | const el = document.querySelector(`[data-index="${task.index}"]`);
628 | const p = el.children[1];
629 | const input = document.createElement('input');
630 | input.type = 'text';
631 | input.value = p.textContent;
632 | input.id = task.index;
633 | el.insertBefore(input, p);
634 | el.removeChild(p);
635 | input.focus();
636 | input.select();
637 | input.classList.add('edit');
638 | });
639 | }
640 |
641 | function createTaskHtml(task) {
642 | li = document.createElement('li');
643 | li.classList.add('task-li');
644 | li.innerHTML = `
645 |
646 |
647 |
${task.description}
648 |
649 |
650 |
651 |
652 |
653 | `;
654 | ul.appendChild(li);
655 | const btn = document.getElementById(`edit-${task.index}`);
656 | prepareEdit(task, btn);
657 | }
658 |
659 | function loadTasks() {
660 | tasks.forEach((task) => {
661 | createTaskHtml(task);
662 | });
663 | }
664 |
665 | loadTasks();
666 |
667 | function addTask() {
668 | ul.innerHTML = '';
669 | tasks.forEach((task) => {
670 | createTaskHtml(task);
671 | });
672 | }
673 |
674 | function removeTask(e) {
675 | if (e.target.classList.contains('close-button')) {
676 | const deletedIndex = e.target.parentElement.parentElement.dataset.index;
677 | const toBeUpdatedTasks = tasks.slice(deletedIndex, tasks.length);
678 | toBeUpdatedTasks.forEach((task) => {
679 | const el = document.querySelector(`[data-index="${task.index}"]`);
680 | el.dataset.index = task.index - 1;
681 | task.index -= 1;
682 | });
683 | e.target.parentElement.parentElement.remove();
684 | tasks.splice(deletedIndex - 1, 1);
685 | localStorage.setItem('tasks', JSON.stringify(tasks));
686 | }
687 | }
688 |
689 | form.addEventListener('submit', (e) => {
690 | e.preventDefault();
691 | const task = new _modules_Task_js__WEBPACK_IMPORTED_MODULE_1__["default"](input.value, tasks.length + 1);
692 | tasks.push(task);
693 | localStorage.setItem('tasks', JSON.stringify(tasks));
694 | addTask();
695 | input.value = '';
696 | });
697 |
698 | ul.addEventListener('click', removeTask);
699 |
700 | ul.addEventListener('keypress', (e) => {
701 | if (e.key === 'Enter') {
702 | const task = tasks.find((t) => t.index === parseInt(e.target.id, 10));
703 | task.description = e.target.value;
704 | localStorage.setItem('tasks', JSON.stringify(tasks));
705 | const p = document.createElement('p');
706 | p.textContent = e.target.value;
707 | const parent = document.querySelector(`[data-index="${e.target.id}"]`);
708 | parent.insertBefore(p, e.target);
709 | parent.removeChild(e.target);
710 | }
711 | });
712 |
713 | function wrapMarkAsCompleted(e) {
714 | (0,_modules_completed_js__WEBPACK_IMPORTED_MODULE_2__.markAsCompleted)(e, tasks);
715 | }
716 |
717 | ul.addEventListener('click', wrapMarkAsCompleted);
718 |
719 | function wrapclearAllCompletedTasks() {
720 | (0,_modules_completed_js__WEBPACK_IMPORTED_MODULE_2__.clearAllCompletedTasks)(tasks);
721 | }
722 |
723 | clearBtn.addEventListener('click', wrapclearAllCompletedTasks);
724 |
725 | })();
726 |
727 | /******/ })()
728 | ;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-setup",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": true,
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "webpack serve --open",
9 | "build": "webpack"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/ahmedtaa/webpack.git"
14 | },
15 | "keywords": [],
16 | "author": "",
17 | "license": "ISC",
18 | "bugs": {
19 | "url": "https://github.com/ahmedtaa/webpack/issues"
20 | },
21 | "homepage": "https://github.com/ahmedtaa/webpack#readme",
22 | "devDependencies": {
23 | "babel-eslint": "^10.1.0",
24 | "css-loader": "^6.5.1",
25 | "eslint": "^7.32.0",
26 | "eslint-config-airbnb-base": "^14.2.1",
27 | "eslint-plugin-import": "^2.25.4",
28 | "hint": "^6.1.9",
29 | "html-webpack-plugin": "^5.5.0",
30 | "style-loader": "^3.3.1",
31 | "stylelint": "^13.13.1",
32 | "stylelint-config-standard": "^21.0.0",
33 | "stylelint-csstree-validator": "^1.9.0",
34 | "stylelint-scss": "^3.21.0",
35 | "webpack": "^5.65.0",
36 | "webpack-cli": "^4.9.1",
37 | "webpack-dev-server": "^4.7.2"
38 | },
39 | "dependencies": {
40 | "lodash": "^4.17.21"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | To Do List
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
24 |
26 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 | import Task from './modules/Task.js';
3 | import { clearAllCompletedTasks, markAsCompleted } from './modules/completed.js';
4 |
5 | const form = document.querySelector('.todo-add');
6 | const input = document.querySelector('.form-field');
7 | const ul = document.getElementById('todo-list');
8 | let li;
9 | const clearBtn = document.querySelector('.todo-clear');
10 |
11 | let tasks;
12 |
13 | if (localStorage.getItem('tasks') === null) {
14 | tasks = [];
15 | } else {
16 | tasks = [];
17 | Array.from(JSON.parse(localStorage.getItem('tasks'))).forEach((task) => {
18 | tasks.push(new Task(task.description, task.index, task.completed));
19 | });
20 | }
21 |
22 | function prepareEdit(task, btn) {
23 | btn.addEventListener('click', () => {
24 | const el = document.querySelector(`[data-index="${task.index}"]`);
25 | const p = el.children[1];
26 | const input = document.createElement('input');
27 | input.type = 'text';
28 | input.value = p.textContent;
29 | input.id = task.index;
30 | el.insertBefore(input, p);
31 | el.removeChild(p);
32 | input.focus();
33 | input.select();
34 | input.classList.add('edit');
35 | });
36 | }
37 |
38 | function createTaskHtml(task) {
39 | li = document.createElement('li');
40 | li.classList.add('task-li');
41 | li.innerHTML = `
42 |
43 |
44 |
${task.description}
45 |
46 |
47 |
48 |
49 |
50 | `;
51 | ul.appendChild(li);
52 | const btn = document.getElementById(`edit-${task.index}`);
53 | prepareEdit(task, btn);
54 | }
55 |
56 | function loadTasks() {
57 | tasks.forEach((task) => {
58 | createTaskHtml(task);
59 | });
60 | }
61 |
62 | loadTasks();
63 |
64 | function addTask() {
65 | ul.innerHTML = '';
66 | tasks.forEach((task) => {
67 | createTaskHtml(task);
68 | });
69 | }
70 |
71 | function removeTask(e) {
72 | if (e.target.classList.contains('close-button')) {
73 | const deletedIndex = e.target.parentElement.parentElement.dataset.index;
74 | const toBeUpdatedTasks = tasks.slice(deletedIndex, tasks.length);
75 | toBeUpdatedTasks.forEach((task) => {
76 | const el = document.querySelector(`[data-index="${task.index}"]`);
77 | el.dataset.index = task.index - 1;
78 | task.index -= 1;
79 | });
80 | e.target.parentElement.parentElement.remove();
81 | tasks.splice(deletedIndex - 1, 1);
82 | localStorage.setItem('tasks', JSON.stringify(tasks));
83 | }
84 | }
85 |
86 | form.addEventListener('submit', (e) => {
87 | e.preventDefault();
88 | const task = new Task(input.value, tasks.length + 1);
89 | tasks.push(task);
90 | localStorage.setItem('tasks', JSON.stringify(tasks));
91 | addTask();
92 | input.value = '';
93 | });
94 |
95 | ul.addEventListener('click', removeTask);
96 |
97 | ul.addEventListener('keypress', (e) => {
98 | if (e.key === 'Enter') {
99 | const task = tasks.find((t) => t.index === parseInt(e.target.id, 10));
100 | task.description = e.target.value;
101 | localStorage.setItem('tasks', JSON.stringify(tasks));
102 | const p = document.createElement('p');
103 | p.textContent = e.target.value;
104 | const parent = document.querySelector(`[data-index="${e.target.id}"]`);
105 | parent.insertBefore(p, e.target);
106 | parent.removeChild(e.target);
107 | }
108 | });
109 |
110 | function wrapMarkAsCompleted(e) {
111 | markAsCompleted(e, tasks);
112 | }
113 |
114 | ul.addEventListener('click', wrapMarkAsCompleted);
115 |
116 | function wrapclearAllCompletedTasks() {
117 | clearAllCompletedTasks(tasks);
118 | }
119 |
120 | clearBtn.addEventListener('click', wrapclearAllCompletedTasks);
121 |
--------------------------------------------------------------------------------
/src/modules/Task.js:
--------------------------------------------------------------------------------
1 | export default class Task {
2 | constructor(description, index, completed = false) {
3 | this.description = description;
4 | this.completed = completed;
5 | this.index = index;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/modules/completed.js:
--------------------------------------------------------------------------------
1 | export function markAsCompleted(e, tasks) {
2 | const completedIndex = e.target.parentElement.dataset.index - 1;
3 | if (e.target.checked) {
4 | e.target.nextElementSibling.classList.add('done');
5 | tasks[completedIndex].completed = true;
6 | } else {
7 | e.target.nextElementSibling.classList.remove('done');
8 | tasks[completedIndex].completed = false;
9 | }
10 | localStorage.setItem('tasks', JSON.stringify(tasks));
11 | }
12 |
13 | export function clearAllCompletedTasks(tasks) {
14 | document.querySelectorAll('.done').forEach((task) => {
15 | const deletedIndex = task.parentElement.dataset.index;
16 | const toBeUpdatedTasks = tasks.slice(deletedIndex, tasks.length);
17 | toBeUpdatedTasks.forEach((task) => {
18 | const el = document.querySelector(`[data-index="${task.index}"]`);
19 | el.dataset.index = task.index - 1;
20 | task.index -= 1;
21 | });
22 | tasks.splice(deletedIndex - 1, 1);
23 | task.parentElement.parentElement.remove();
24 | });
25 | localStorage.setItem('tasks', JSON.stringify(tasks));
26 | }
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #f6f6f6;
3 | }
4 |
5 | .container {
6 | border: 1px solid;
7 | background-color: #fff;
8 | width: 50%;
9 | margin: auto;
10 | }
11 |
12 | .header {
13 | display: flex;
14 | justify-content: space-between;
15 | padding: 10px;
16 | }
17 |
18 | .header button {
19 | background-color: transparent;
20 | border: none;
21 | cursor: pointer;
22 | }
23 |
24 | .todo-add {
25 | display: flex;
26 | padding: 10px;
27 | }
28 |
29 | .todo-add button {
30 | background-color: transparent;
31 | border: none;
32 | cursor: pointer;
33 | }
34 |
35 | .form-field {
36 | font-family: inherit;
37 | width: 100%;
38 | border: 0;
39 | border-bottom: 2px solid #9b9b9b;
40 | outline: 0;
41 | font-size: 1.3rem;
42 | color: black;
43 | padding: 7px 0;
44 | background: transparent;
45 | transition: border-color 0.2s;
46 | }
47 |
48 | ul {
49 | list-style: none;
50 | padding: 10px;
51 | }
52 |
53 | .task {
54 | display: flex;
55 | align-items: center;
56 | justify-content: flex-start;
57 | gap: 10px;
58 | }
59 |
60 | .btns {
61 | margin-left: auto;
62 | display: flex;
63 | gap: 40px;
64 | }
65 |
66 | .close-button {
67 | transform: rotate(45deg);
68 | cursor: pointer;
69 | font-size: 30px;
70 | color: red;
71 | }
72 |
73 | .edit {
74 | border-color: transparent;
75 | height: 40px;
76 | }
77 |
78 | .edit:focus-visible {
79 | outline: green auto 1px;
80 | font-size: 15px;
81 | }
82 |
83 | .done {
84 | text-decoration: line-through;
85 | opacity: 0.5;
86 | }
87 |
88 | .scroll {
89 | background-color: transparent;
90 | border: none;
91 | cursor: pointer;
92 | margin-left: auto;
93 | }
94 |
95 | .footer {
96 | background-color: #f6f6f6;
97 | height: 50px;
98 | border-top: 1px solid;
99 | display: flex;
100 | justify-content: center;
101 | opacity: 0.5;
102 | }
103 |
104 | .footer button {
105 | background-color: transparent;
106 | border: none;
107 | cursor: pointer;
108 | font-size: 20px;
109 | }
110 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 |
4 | module.exports = {
5 | mode: 'none',
6 | entry: './src/index.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 | clean: true,
19 | },
20 | module: {
21 | rules: [
22 | {
23 | test: /\.css$/i,
24 | use: ['style-loader', 'css-loader'],
25 | },
26 | ],
27 | },
28 | };
29 |
--------------------------------------------------------------------------------