Skip to content
Snippets Groups Projects
Commit a8ff5d93 authored by Truong The Kha's avatar Truong The Kha
Browse files

Kha Changes

parent 2f0d1382
Branches
No related tags found
1 merge request!4Kha Changes
{
"name": "npm",
"version": "0.0.0",
......@@ -8,6 +9,7 @@
"name": "npm",
"version": "0.0.0",
"dependencies": {
"mammoth": "^1.9.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
......@@ -1394,6 +1396,15 @@
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0"
}
},
"node_modules/@xmldom/xmldom": {
"version": "0.8.10",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
......@@ -1464,6 +1475,32 @@
"dev": true,
"license": "MIT"
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/bluebird": {
"version": "3.4.7",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
"integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
......@@ -1590,6 +1627,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
......@@ -1637,6 +1680,21 @@
"dev": true,
"license": "MIT"
},
"node_modules/dingbat-to-unicode": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz",
"integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==",
"license": "BSD-2-Clause"
},
"node_modules/duck": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/duck/-/duck-0.1.12.tgz",
"integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==",
"license": "BSD",
"dependencies": {
"underscore": "^1.13.1"
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.143",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.143.tgz",
......@@ -2044,6 +2102,12 @@
"node": ">= 4"
}
},
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
......@@ -2071,6 +2135,12 @@
"node": ">=0.8.19"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
......@@ -2094,6 +2164,12 @@
"node": ">=0.10.0"
}
},
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"license": "MIT"
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
......@@ -2168,6 +2244,18 @@
"node": ">=6"
}
},
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"license": "(MIT OR GPL-3.0-or-later)",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
......@@ -2192,6 +2280,15 @@
"node": ">= 0.8.0"
}
},
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
......@@ -2215,6 +2312,17 @@
"dev": true,
"license": "MIT"
},
"node_modules/lop": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/lop/-/lop-0.4.2.tgz",
"integrity": "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==",
"license": "BSD-2-Clause",
"dependencies": {
"duck": "^0.1.12",
"option": "~0.2.1",
"underscore": "^1.13.1"
}
},
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
......@@ -2225,6 +2333,39 @@
"yallist": "^3.0.2"
}
},
"node_modules/mammoth": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/mammoth/-/mammoth-1.9.0.tgz",
"integrity": "sha512-F+0NxzankQV9XSUAuVKvkdQK0GbtGGuqVnND9aVf9VSeUA82LQa29GjLqYU6Eez8LHqSJG3eGiDW3224OKdpZg==",
"license": "BSD-2-Clause",
"dependencies": {
"@xmldom/xmldom": "^0.8.6",
"argparse": "~1.0.3",
"base64-js": "^1.5.1",
"bluebird": "~3.4.0",
"dingbat-to-unicode": "^1.0.1",
"jszip": "^3.7.1",
"lop": "^0.4.2",
"path-is-absolute": "^1.0.0",
"underscore": "^1.13.1",
"xmlbuilder": "^10.0.0"
},
"bin": {
"mammoth": "bin/mammoth"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/mammoth/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
......@@ -2278,6 +2419,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/option": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/option/-/option-0.2.4.tgz",
"integrity": "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==",
"license": "BSD-2-Clause"
},
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
......@@ -2328,6 +2475,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
......@@ -2351,6 +2504,15 @@
"node": ">=8"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
......@@ -2477,6 +2639,21 @@
"node": ">=0.10.0"
}
},
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
......@@ -2527,6 +2704,12 @@
"fsevents": "~2.3.2"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/scheduler": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
......@@ -2543,6 +2726,12 @@
"semver": "bin/semver.js"
}
},
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
"license": "MIT"
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
......@@ -2576,6 +2765,21 @@
"node": ">=0.10.0"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"license": "BSD-3-Clause"
},
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
......@@ -2632,6 +2836,12 @@
"node": ">= 0.8.0"
}
},
"node_modules/underscore": {
"version": "1.13.7",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
"integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
"license": "MIT"
},
"node_modules/update-browserslist-db": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
......@@ -2673,6 +2883,12 @@
"punycode": "^2.1.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/vite": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.3.tgz",
......@@ -2774,6 +2990,15 @@
"node": ">=0.10.0"
}
},
"node_modules/xmlbuilder": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz",
"integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==",
"license": "MIT",
"engines": {
"node": ">=4.0"
}
},
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
......
......
......@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"mammoth": "^1.9.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
......
......
......@@ -42,3 +42,96 @@
#title-description{
text-align: center;
}
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
* {
font-family: 'Poppins', sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #8758ff;
display: flex;
justify-content: center;
align-items: center;
}
.App {
text-align: center;
}
h1 {
color: #fff;
margin-bottom: 0.5rem;
font-size: 1.75rem;
}
.TodoWrapper {
background: #1A1A40;
margin-top: 5rem;
padding: 2rem;
border-radius: 5px;
}
.TodoForm {
width: 100%;
margin-bottom: 1rem;
}
.todo-input {
outline: none;
background: none;
border: 1px solid #8758ff;
padding: 0.5rem 1rem;
margin-top: 1rem;
margin-bottom: 2rem;
width: 300px;
color: #fff;
}
.todo-input::placeholder {
color: #ffffff4d;
}
.todo-btn {
background: #8758ff;
color: #fff;
border: none;
padding: 0.55rem;
cursor: pointer;
}
.Todo {
display: flex;
justify-content: space-between;
align-items: center;
background: #8758ff;
color: #fff;
padding: 0.75rem 1rem;
border-radius: 5px;
margin-bottom: 1rem;
}
.fa-trash {
margin-left: 0.75rem;
}
.incompleted {
color: #fff;
cursor: pointer;
}
.completed {
color: #c5aeff;
text-decoration: line-through;
cursor: pointer;
}
.edit-icon,
.delete-icon {
cursor: pointer;
}
import TimeDuration from "./components/TimeDuration"
import Title from "./components/Title"
import FileInput from "./components/FileInput"
import TodoList from "./components/ToDoList"
function App() {
return (
<>
<div className="page-container">
<div className="page-container" style = {{display : "inline-flex"}}>
<Title/>
<TimeDuration/>
<FileInput />
<TodoList />
</div>
</>
)
......
......
import { useRef, useState } from "react";
import '../fileinput.css';
import mammoth from "mammoth";
export function FileInput() {
const inputRef = useRef();
const [uploadedFiles, setUploadedFiles] = useState([]);
// Handle file selection and processing
const handleOnChange = async (event) => {
if (event.target.files && event.target.files.length > 0) {
const file = event.target.files[0];
let content = null;
// Process file based on type
if (file.type === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") {
const reader = new FileReader();
reader.onload = async (e) => {
const arrayBuffer = e.target.result;
try {
const result = await mammoth.extractRawText({ arrayBuffer });
content = result.value;
setUploadedFiles((prev) => [...prev, { file, content, url: URL.createObjectURL(file) }]);
} catch (error) {
console.error("Error parsing DOCX file:", error);
}
};
reader.readAsArrayBuffer(file);
return; // Exit early to avoid duplicate processing
}
// For text files and JSON
if (file.type.includes("text") || file.type.includes("application/json")) {
const reader = new FileReader();
reader.onload = (e) => {
content = e.target.result;
setUploadedFiles((prev) => [...prev, { file, content, url: URL.createObjectURL(file) }]);
};
reader.readAsText(file);
}
// For images
else if (file.type.includes("image")) {
const reader = new FileReader();
reader.onload = (e) => {
content = e.target.result;
setUploadedFiles((prev) => [...prev, { file, content, url: URL.createObjectURL(file) }]);
};
reader.readAsDataURL(file);
}
// For PDFs, videos, audio, and other files
else {
content = URL.createObjectURL(file);
setUploadedFiles((prev) => [...prev, { file, content, url: content }]);
}
}
};
// Trigger file input click
const onChooseFile = () => {
inputRef.current.click();
};
// Remove a specific file and clean up its URL
const removeFile = (fileToRemove) => {
setUploadedFiles((prev) =>
prev.filter((item) => {
if (item.file === fileToRemove) {
URL.revokeObjectURL(item.url); // Clean up object URL
return false;
}
return true;
})
);
};
// Render file content based on file type
const renderFileContent = (item) => {
const { file, content } = item;
if (file.type.includes("text") || file.type.includes("application/json") || file.type === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") {
return (
<div className="file-preview text-content">
<h3>Text Content:</h3>
<pre
style={{
maxHeight: "300px",
overflow: "auto",
whiteSpace: "pre-wrap",
border: "1px solid #ccc",
padding: "10px",
}}
>
{content}
</pre>
</div>
);
} else if (file.type.includes("image")) {
return (
<div className="file-preview image-content">
<h3>Image Preview:</h3>
<img src={content} alt="Preview" style={{ maxWidth: "100%", maxHeight: "300px" }} />
</div>
);
} else if (file.type === "application/pdf") {
return (
<div className="file-preview pdf-content">
<h3>PDF Preview:</h3>
<iframe
src={content}
title="PDF Preview"
width="100%"
height="500px"
style={{ border: "1px solid #ccc" }}
/>
</div>
);
} else if (file.type.includes("video")) {
return (
<div className="file-preview video-content">
<h3>Video Preview:</h3>
<video src={content} controls style={{ maxWidth: "100%", maxHeight: "400px" }}>
Your browser does not support the video tag.
</video>
</div>
);
} else if (file.type.includes("audio")) {
return (
<div className="file-preview audio-content">
<h3>Audio Preview:</h3>
<audio src={content} controls style={{ width: "100%" }}>
Your browser does not support the audio tag.
</audio>
</div>
);
}
return <p>This file type ({file.type}) cannot be previewed</p>;
};
return (
<div style={{ margin: "20px", maxWidth: "800px" }}>
<input
type="file"
ref={inputRef}
onChange={handleOnChange}
style={{ display: "none" }}
accept="text/*,image/*,application/pdf,video/*,audio/*,application/json,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
/>
<button className="file-btn" onClick={onChooseFile}>
<span className="material-symbols-rounded">upload</span> Upload file
</button>
{uploadedFiles.length > 0 && (
<div className="uploaded-files">
{uploadedFiles.map((item, index) => (
<div key={index} className="selected-file" style={{ marginBottom: "20px" }}>
<p>
{item.file.name} ({Math.round(item.file.size / 1024)} KB) - {item.file.type}
</p>
<button className="material-symbols-rounded" onClick={() => removeFile(item.file)}>
delete
</button>
{renderFileContent(item)}
</div>
))}
</div>
)}
</div>
);
}
export default FileInput
\ No newline at end of file
import { useState } from "react";
export function TodoList() {
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState("");
function handleInputChange(event) {
setNewTask(event.target.value);
};
function addTask() {
if(newTask.trim() !== "") {
setTasks(t => [...t, newTask]);
setNewTask("");
}
};
function deleteTask(index) {
const updatedTasks = tasks.filter((_, i) => i !== index);
setTasks(updatedTasks);
};
function moveTaskUp(index) {
if(index > 0){
const updatedTasks = [...tasks];
[updatedTasks[index], updatedTasks[index -1]] = [updatedTasks[index -1], updatedTasks[index]];
setTasks(updatedTasks);
}
};
function moveTaskDown(index) {
if(index < tasks.length - 1){
const updatedTasks = [...tasks];
[updatedTasks[index], updatedTasks[index +1]] = [updatedTasks[index +1], updatedTasks[index]];
setTasks(updatedTasks);
}
};
return(
<div className="to-do-list">
<h1>Tasks to do</h1>
<div>
<input
type="text"
placeholder="Enter a task"
value = {newTask}
onChange={handleInputChange} />
<button className="add-btn"
onClick={addTask}>Add Task
</button>
</div>
<ol>
{tasks.map((task,index) =>
<li key={index}>
<span className="text">{task}</span>
<button
className="delete-btn"
onClick={() => deleteTask(index)}>
Delete
</button>
<button
className="move-btn"
onClick={() => moveTaskUp(index)}>
^
</button>
<button
className="move-btn"
onClick={() => moveTaskDown(index)}>
V
</button>
</li>
)}
</ol>
</div>
);
}
export default TodoList;
.file-btn {
width: 250px;
height: 150px;
font-size: 18px;
font-weight: 500;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 15px;
color: #8A3FFC;
background-color: #fff;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s ease;
}
.file-btn:hover{
color: #8a3ffc;
background-color: #fff;
}
.file-btn span {
width: 50px;
height: 50px;
font-size: 30px;
color: #8a3ffc;
display: flex;
align-items: center;
justify-content: center;
border-radius: 25px;
background-color: #f3ecff;
}
.selected-file {
display: flex;
align-items: center;
justify-content: space-between;
background-color: #f3ecff;
border: 1px solid #e8d9fe;
border-radius: 20px;
margin-top: 20px;
color: black;
}
.selected-file p {
color: black;
}
.selected-file button {
width: 40px;
height: 40px;
display: flex;
justify-content: center;
background-color: transparent;
border: none;
border-radius: 20px;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment