diff --git a/index.html b/index.html index f7ac4e4..89fa055 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,40 @@ - - - - - Todo - - -
- - - + + + + + + + + + Todo + + + +
+ + + + \ No newline at end of file diff --git a/package.json b/package.json index caf6289..ab8f527 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,12 @@ "preview": "vite preview" }, "dependencies": { + "@tailwindcss/vite": "^4.1.7", + "date-fns": "^4.1.0", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "tailwindcss": "^4.1.7", + "zustand": "^5.0.4" }, "devDependencies": { "@eslint/js": "^9.21.0", diff --git a/public/assets/check-mark.png b/public/assets/check-mark.png new file mode 100644 index 0000000..8bfe07c Binary files /dev/null and b/public/assets/check-mark.png differ diff --git a/public/assets/close.png b/public/assets/close.png new file mode 100644 index 0000000..a941383 Binary files /dev/null and b/public/assets/close.png differ diff --git a/public/assets/filter.png b/public/assets/filter.png new file mode 100644 index 0000000..2ac4883 Binary files /dev/null and b/public/assets/filter.png differ diff --git a/public/assets/logo1.png b/public/assets/logo1.png new file mode 100644 index 0000000..c527a10 Binary files /dev/null and b/public/assets/logo1.png differ diff --git a/public/assets/note-background-smaller.webp b/public/assets/note-background-smaller.webp new file mode 100644 index 0000000..b2c6ea6 Binary files /dev/null and b/public/assets/note-background-smaller.webp differ diff --git a/public/assets/note-background.webp b/public/assets/note-background.webp new file mode 100644 index 0000000..9332eed Binary files /dev/null and b/public/assets/note-background.webp differ diff --git a/public/assets/set.png b/public/assets/set.png new file mode 100644 index 0000000..a99dc47 Binary files /dev/null and b/public/assets/set.png differ diff --git a/public/assets/signature.png b/public/assets/signature.png new file mode 100644 index 0000000..c5820a4 Binary files /dev/null and b/public/assets/signature.png differ diff --git a/public/assets/user.png b/public/assets/user.png new file mode 100644 index 0000000..9afed7b Binary files /dev/null and b/public/assets/user.png differ diff --git a/src/App.jsx b/src/App.jsx index 5427540..25041ff 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,5 +1,9 @@ +import { AppLayout } from "./components/AppLayout" + export const App = () => { return ( -

React Boilerplate

+ <> + + ) } diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx new file mode 100644 index 0000000..d83ab2e --- /dev/null +++ b/src/components/AppLayout.tsx @@ -0,0 +1,12 @@ +import { HeroMessage } from "./HeroMessage" +import { TaskArea } from "./TaskArea" + +export const AppLayout = () => { + return ( + +
+ + +
+ ) +} \ No newline at end of file diff --git a/src/components/EmptyState.tsx b/src/components/EmptyState.tsx new file mode 100644 index 0000000..0170727 --- /dev/null +++ b/src/components/EmptyState.tsx @@ -0,0 +1,8 @@ +export const EmptyState = () => { + return ( +
+

No tasks yet

+

Click “New Task +” to get started

+
+ ) +} \ No newline at end of file diff --git a/src/components/HeroMessage.tsx b/src/components/HeroMessage.tsx new file mode 100644 index 0000000..e59b353 --- /dev/null +++ b/src/components/HeroMessage.tsx @@ -0,0 +1,21 @@ + + +export const HeroMessage = () => { + return ( +
+
+ Logo + User +
+
+

From Clutter to Done with Done-ly

+

Make it simple

+ +
+
+ ); +} \ No newline at end of file diff --git a/src/components/TaskArea.tsx b/src/components/TaskArea.tsx new file mode 100644 index 0000000..f095038 --- /dev/null +++ b/src/components/TaskArea.tsx @@ -0,0 +1,67 @@ +import { TaskButtons } from "./TaskButtons" +import { useState } from "react" +import { TaskForm } from "./TaskForm" +import { TaskList } from "./TaskList" +import { EmptyState } from "./EmptyState" +import { useTaskStore } from "../stores/useTaskStore" +import { TaskCount } from "./TaskCount" + + +export const TaskArea = () => { + const [showForm, setShowForm] = useState(false) + + const [filter, setFilter] = useState<"all" | "completed" | "uncompleted">("all") + const tasks = useTaskStore((state) => state.tasks) + + const filteredTasks = tasks.filter((task) => { + if (filter === "completed") return task.completed + if (filter === "uncompleted") return !task.completed + return true // For "all" filter + }) + + return ( +
+ +
+ setShowForm(true)} + /> + + {tasks.length > 0 && ( +
+ {["all", "completed", "uncompleted"].map((type) => ( + + ))} +
+ )} +
+ + + {showForm && ( +
+ setShowForm(false)} /> +
+ )} + + {tasks.length === 0 && !showForm && } + + { + filteredTasks.length > 0 && ( +
+
+ +
+ +
+ ) + } +
+ ) +} \ No newline at end of file diff --git a/src/components/TaskButtons.tsx b/src/components/TaskButtons.tsx new file mode 100644 index 0000000..93322c2 --- /dev/null +++ b/src/components/TaskButtons.tsx @@ -0,0 +1,20 @@ +type TaskButtonsProps = { + text: string + onClick: () => void +} + + +export const TaskButtons = ({ text, onClick }: TaskButtonsProps) => { + console.log("TaskButtons rendered") + + return ( + <> + + + ) +} \ No newline at end of file diff --git a/src/components/TaskCount.tsx b/src/components/TaskCount.tsx new file mode 100644 index 0000000..d6a7bd2 --- /dev/null +++ b/src/components/TaskCount.tsx @@ -0,0 +1,17 @@ +import { useTaskStore } from "../stores/useTaskStore" + +export const TaskCount = () => { + const totalTasks = useTaskStore((state) => state.tasks.length) + const completedTasks = useTaskStore((state) => + state.tasks.filter((task) => task.completed).length + ) + const uncompletedTasks = useTaskStore((state) => + state.tasks.filter((task) => !task.completed).length + ) + + return ( +
+

Completed: {completedTasks}/{totalTasks}

+
+ ) +} \ No newline at end of file diff --git a/src/components/TaskForm.tsx b/src/components/TaskForm.tsx new file mode 100644 index 0000000..aeea04a --- /dev/null +++ b/src/components/TaskForm.tsx @@ -0,0 +1,84 @@ +import { useEffect, useState, useRef } from "react" +import { useTaskStore } from "../stores/useTaskStore" + +type TaskFormProps = { + onClose: () => void +} + + +export const TaskForm = ({ onClose }: TaskFormProps) => { + const [text, setText] = useState("") + const [checked, setChecked] = useState(false) + const [error, setError] = useState("") + const textareaRef = useRef(null) + const addTask = useTaskStore((state) => state.addTask) + + useEffect(() => { + textareaRef.current?.focus() + }, []) + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault() + if (text.trim() === "") { + setError("Please enter a task") + textareaRef.current?.focus() + return + } + addTask(text) + setText("") + setChecked(false) + onClose() + } + + return ( + +
+ +
+ +