diff --git a/README.md b/README.md index 67e65a0..02a2850 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,65 @@ # DevDone - A Developer's Todo App -A simple, clean, and efficient todo list application built with vanilla JavaScript, HTML, and CSS. +🚀 A beginner-friendly open-source project from the DevDotCom Community to help developers take their first step into open source! This simple and efficient task management app is built using Flask, JavaScript, HTML, and CSS to make learning fun and easy. -## Features +🌟 Features -- Add new tasks -- Mark tasks as complete -- Delete tasks -- Persistent storage using localStorage -- Clean and responsive design -- Keyboard accessible -- Mobile-friendly interface +Add Tasks: Easily create and manage tasks. -## Getting Started +Mark as Completed: Toggle tasks as done. -1. Clone the repository or download the files -2. Open `index.html` in your web browser +Delete Tasks: Remove completed tasks. -No build process or dependencies required! +Persistent Storage: Saves tasks using JSON. -## Project Structure +Minimalistic UI: Clean and user-friendly design. -``` +🛠️ Technologies Used + +Backend: Flask (Python) + +Frontend: HTML, CSS, JavaScript + +Storage: JSON + +📁 Project Structure DevDone/ -├── index.html # Main HTML structure -├── styles.css # Styling and layout -├── script.js # Application logic -└── README.md # Project documentation -``` +│── app.py # Flask backend +│── requirements.txt # Dependencies +│── static/ +│ ├── styles.css # Stylesheet +│ ├── script.js # Frontend logic +│── templates/ +│ ├── index.html # UI template +│── data/ +│ ├── todos.json # Task storage +│── README.md # Documentation + +🚀 Getting Started + +Prerequisites + +Python 3 installed -## Usage +Install Flask using: +pip install flask -- Type your task in the input field -- Click "Add Task" or press Enter to add the task -- Check the checkbox to mark a task as complete -- Click the "Delete" button to remove a task +# Clone the repository +git clone https://github.com/your-username/developer-todo-app.git +cd DevDone -## Browser Support +# Create a Simple environment using conda or pip -Works in all modern browsers (Chrome, Firefox, Safari, Edge) +# Install dependencies +pip install -r requirements.txt -## Contributing +# Run the Flask application +python app.py -1. Fork the repository -2. Create a new branch (`git checkout -b feature/improvement`) -3. Make your changes -4. Commit your changes (`git commit -am 'Add new feature'`) -5. Push to the branch (`git push origin feature/improvement`) -6. Create a Pull Request +🤝 Contributing -### Development Guidelines -- Follow existing code style and formatting -- Test your changes thoroughly -- Update documentation as needed -- Keep pull requests focused on a single feature or fix +This is an open-source project built for beginners! Contributions are highly encouraged. Feel free to fork, raise issues, or submit pull requests to improve this project. -## License +📜 License -MIT License +This project is licensed under the MIT License. \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..67e7b29 --- /dev/null +++ b/app.py @@ -0,0 +1,63 @@ +from flask import Flask, render_template, request, jsonify +import json +import os + +app = Flask(__name__) + +DATA_FILE = "data/todos.json" + +# Ensure data directory exists +os.makedirs("data", exist_ok=True) + +# Load todos from file +def load_todos(): + if os.path.exists(DATA_FILE): + with open(DATA_FILE, "r") as file: + return json.load(file) + return [] + +# Save todos to file +def save_todos(todos): + with open(DATA_FILE, "w") as file: + json.dump(todos, file, indent=4) + +@app.route("/") +def home(): + return render_template("index.html") + +@app.route("/todos", methods=["GET"]) +def get_todos(): + return jsonify(load_todos()) + +@app.route("/todos", methods=["POST"]) +def add_todo(): + todos = load_todos() + data = request.get_json() + new_todo = { + "id": data["id"], + "text": data["text"], + "completed": False + } + todos.append(new_todo) + save_todos(todos) + return jsonify(new_todo), 201 + +@app.route("/todos/", methods=["DELETE"]) +def delete_todo(todo_id): + todos = load_todos() + todos = [todo for todo in todos if todo["id"] != todo_id] + save_todos(todos) + return jsonify({"message": "Todo deleted"}), 200 + +@app.route("/todos/", methods=["PUT"]) +def update_todo(todo_id): + todos = load_todos() + for todo in todos: + if todo["id"] == todo_id: + todo["completed"] = not todo["completed"] + break + save_todos(todos) + return jsonify({"message": "Todo updated"}), 200 + +if __name__ == "__main__": + app.run(debug=True) diff --git a/index.html b/index.html deleted file mode 100644 index 84b934a..0000000 --- a/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - Developer's Todo App - - - - -
-

Developer's Todo List

-

Number of Tasks:

-
- - -
-
    -
    - - - diff --git a/script.js b/script.js deleted file mode 100644 index 17dad44..0000000 --- a/script.js +++ /dev/null @@ -1,72 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - const todoForm = document.getElementById("todo-form"); - const todoInput = document.getElementById("todo-input"); - const todoList = document.getElementById("todo-list"); - - // Load todos from localStorage - let todos = JSON.parse(localStorage.getItem("todos")) || []; - - const saveTodos = () => { - localStorage.setItem("todos", JSON.stringify(todos)); - }; - - const renderTodos = () => { - todoList.innerHTML = ""; - todos.forEach((todo) => { - const li = document.createElement("li"); - li.className = "todo-item"; - li.innerHTML = ` - - ${todo.text} - - `; - - const checkbox = li.querySelector("input"); - checkbox.addEventListener("change", () => { - todo.completed = checkbox.checked; - li.querySelector("span").classList.toggle("completed"); - saveTodos(); - countListItems(); // Update task count when a task is checked/unchecked - }); - - const deleteBtn = li.querySelector(".delete-btn"); - deleteBtn.addEventListener("click", () => { - todos = todos.filter((t) => t.id !== todo.id); - li.remove(); - saveTodos(); - countListItems(); // Update task count when a task is deleted - }); - - todoList.appendChild(li); - }); - countListItems(); // Update task count after rendering - }; - - todoForm.addEventListener("submit", (e) => { - e.preventDefault(); - const text = todoInput.value.trim(); - if (text) { - const todo = { - id: Date.now(), - text, - completed: false, - }; - todos.push(todo); - todoInput.value = ""; - saveTodos(); - renderTodos(); - } - }); - - function countListItems() { - const ulElement = document.getElementById('todo-list'); - const liElements = ulElement.getElementsByTagName('li'); - const itemCount = liElements.length; - - // Update the

    element instead of

    element - document.getElementById('itemcount').innerText = `Number of Tasks: ${itemCount}`; - } - - // Initial render - renderTodos(); -}); diff --git a/static/script.js b/static/script.js new file mode 100644 index 0000000..b5d6e81 --- /dev/null +++ b/static/script.js @@ -0,0 +1,67 @@ +document.addEventListener("DOMContentLoaded", () => { + const todoForm = document.getElementById("todo-form"); + const todoInput = document.getElementById("todo-input"); + const todoList = document.getElementById("todo-list"); + const itemCount = document.getElementById("itemcount"); + + // Fetch todos from backend + const fetchTodos = async () => { + const response = await fetch("/todos"); + const todos = await response.json(); + renderTodos(todos); + }; + + // Add a new todo + todoForm.addEventListener("submit", async (e) => { + e.preventDefault(); + const text = todoInput.value.trim(); + if (text) { + const response = await fetch("/todos", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ id: Date.now(), text }) + }); + const newTodo = await response.json(); + renderTodos([...document.todos, newTodo]); + todoInput.value = ""; + } + }); + + // Render Todos + const renderTodos = (todos) => { + document.todos = todos; + todoList.innerHTML = ""; + todos.forEach((todo) => { + const li = document.createElement("li"); + li.className = "todo-item"; + li.innerHTML = ` + + ${todo.text} + + `; + + const checkbox = li.querySelector("input"); + checkbox.addEventListener("change", async () => { + await fetch(`/todos/${todo.id}`, { method: "PUT" }); + fetchTodos(); + }); + + const deleteBtn = li.querySelector(".delete-btn"); + deleteBtn.addEventListener("click", async () => { + await fetch(`/todos/${todo.id}`, { method: "DELETE" }); + fetchTodos(); + }); + + todoList.appendChild(li); + }); + updateTaskCount(todos.length); + }; + + // Update Task Count + const updateTaskCount = (count) => { + itemCount.innerText = `Number of Tasks: ${count}`; + }; + + // Initial fetch + fetchTodos(); +}); diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..5d2b9ed --- /dev/null +++ b/static/style.css @@ -0,0 +1,67 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: Arial, sans-serif; + background: #f5f5f5; +} + +.container { + max-width: 600px; + margin: 2rem auto; + padding: 1rem; +} + +h1 { + text-align: center; + color: #333; +} + +#todo-form { + display: flex; + gap: 0.5rem; + margin-bottom: 1rem; +} + +#todo-input { + flex: 1; + padding: 0.5rem; + border: 1px solid #ddd; + border-radius: 4px; +} + +button { + padding: 0.5rem 1rem; + background: #0066cc; + color: white; + border: none; + cursor: pointer; +} + +#todo-list { + list-style: none; +} + +.todo-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.75rem; + background: white; + border-radius: 4px; + margin-bottom: 0.5rem; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.completed { + text-decoration: line-through; + opacity: 0.7; +} + +.delete-btn { + margin-left: auto; + background: #dc3545; +} diff --git a/styles.css b/styles.css deleted file mode 100644 index dfb8c1c..0000000 --- a/styles.css +++ /dev/null @@ -1,79 +0,0 @@ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, sans-serif; - line-height: 1.6; - background: #f5f5f5; -} - -.container { - max-width: 600px; - margin: 2rem auto; - padding: 1rem; -} - -h1 { - text-align: center; - color: #333; - margin-bottom: 1.5rem; -} - -#todo-form { - display: flex; - gap: 0.5rem; - margin-bottom: 1.5rem; -} - -#todo-input { - flex: 1; - padding: 0.5rem; - font-size: 1rem; - border: 1px solid #ddd; - border-radius: 4px; -} - -button { - padding: 0.5rem 1rem; - background: #0066cc; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; -} - -button:hover { - background: #0052a3; -} - -#todo-list { - list-style: none; -} - -.todo-item { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0.75rem; - background: white; - border-radius: 4px; - margin-bottom: 0.5rem; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); -} - -.completed { - text-decoration: line-through; - opacity: 0.7; -} - -.delete-btn { - margin-left: auto; - background: #dc3545; -} - -.delete-btn:hover { - background: #c82333; -} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..d7178b8 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,21 @@ + + + + + + Developer's Todo App + + + +

    +

    Developer's Todo List

    +

    Number of Tasks: 0

    +
    + + +
    +
      +
      + + +