diff --git a/README.md b/README.md index d1c68b57..99130b73 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -# Todo \ No newline at end of file +# Todo + +## 🚀 Live Demo + +https://task-by-task.netlify.app/ \ No newline at end of file diff --git a/index.html b/index.html index f7ac4e42..b5740376 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,40 @@ - - - - - Todo - - -
- - - + + + + + + + + + To-do List + + + +
+ + + + \ No newline at end of file diff --git a/package.json b/package.json index caf62893..71d3743c 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,14 @@ "preview": "vite preview" }, "dependencies": { + "@tailwindcss/vite": "^4.1.18", + "date-fns": "^4.1.0", + "framer-motion": "^12.26.2", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-datepicker": "^9.1.0", + "react-dom": "^19.0.0", + "tailwindcss": "^4.1.18", + "zustand": "^5.0.10" }, "devDependencies": { "@eslint/js": "^9.21.0", diff --git a/public/darkmode.png b/public/darkmode.png new file mode 100644 index 00000000..9bdb83c5 Binary files /dev/null and b/public/darkmode.png differ diff --git a/public/todolist.png b/public/todolist.png new file mode 100644 index 00000000..a9ef9c8a Binary files /dev/null and b/public/todolist.png differ diff --git a/src/App.jsx b/src/App.jsx index 54275400..cf8ac7b8 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,5 +1,45 @@ +import { useState, useEffect } from "react" +import { Heading } from "./components/Heading" +import { TodoList } from "./components/TodoList" +import { AddTodoToggle } from "./components/AddTodoToggle" +import { TodoForm } from "./components/TodoForm" +import { useTodoStore } from "./stores/todoStore" + export const App = () => { + const [isAdding, setIsAdding] = useState(false) + const darkMode = useTodoStore((state) => state.darkMode) + + useEffect(() => { + if (darkMode) { + document.documentElement.classList.add("dark") + } else { + document.documentElement.classList.remove("dark") + } + }, [darkMode]) + return ( -

React Boilerplate

+
+
+ + +
+ {isAdding && ( + setIsAdding(false)} /> + )} + + +
+ + setIsAdding(true)} /> +
+
) -} +} \ No newline at end of file diff --git a/src/components/AddTodoToggle.jsx b/src/components/AddTodoToggle.jsx new file mode 100644 index 00000000..6692c8aa --- /dev/null +++ b/src/components/AddTodoToggle.jsx @@ -0,0 +1,39 @@ +export const AddTodoToggle = ({ onAdd }) => { + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/src/components/Heading.jsx b/src/components/Heading.jsx new file mode 100644 index 00000000..a43fddd9 --- /dev/null +++ b/src/components/Heading.jsx @@ -0,0 +1,72 @@ +import { format } from "date-fns" +import { useTodoStore } from "../stores/todoStore" + +export const Heading = () => { + const todos = useTodoStore((state) => state.todos) + const completeAllTodos = useTodoStore((state) => state.completeAllTodos) + const darkMode = useTodoStore((state) => state.darkMode) + const toggleDarkMode = useTodoStore((state) => state.toggleDarkMode) + + const totalTodos = todos.length + const completed = todos.filter((todo) => todo.completed).length + const uncompleted = totalTodos - completed + + const today = format(new Date(), "EEE d MMMM") + + return ( +
+
+ +
+

+ To-do list +

+

{today}

+
+ +
+ +

Total: {totalTodos}

+

+ Completed: {completed} +

+

+ Uncompleted: {uncompleted} +

+ + {totalTodos > 0 && ( + + )} +
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/TodoForm.jsx b/src/components/TodoForm.jsx new file mode 100644 index 00000000..0a936ab7 --- /dev/null +++ b/src/components/TodoForm.jsx @@ -0,0 +1,99 @@ +import { useState } from "react" +import DatePicker from "react-datepicker" +import "react-datepicker/dist/react-datepicker.css" +import { useTodoStore } from "../stores/todoStore" + +export const TodoForm = ({ onClose }) => { + const addTodo = useTodoStore((state) => state.addTodo) + + const [text, setText] = useState("") + const [category, setCategory] = useState("General") + const [dueDate, setDueDate] = useState(null) + + + const handleSubmit = (e) => { + e.preventDefault() + if (!text.trim()) return + addTodo(text, category, dueDate || null) + onClose() + } + + return ( +
+