PHP

PHP To-Do App with Drag & Drop Animation

Build a Kanban-style to-do app with drag-and-drop task management, smooth animations, and PHP backend persistence.

PHPJavaScriptCSSAnimationDrag and Drop

Thumbnail for PHP To-Do App with Drag & Drop Animation

Overview

Build a Kanban-style to-do app with three columns (To Do, In Progress, Done). Users can drag tasks between columns with smooth animations, and PHP persists data to a JSON file.

Project Structure

text
todo-kanban/
├── index.php
├── api.php
├── data/tasks.json
└── css/style.css

Backend API (api.php)

php
<?php
header("Content-Type: application/json");
$file = "data/tasks.json";
if (!file_exists($file)) file_put_contents($file, json_encode(["todo"=>[],"progress"=>[],"done"=>[]]));

if ($_SERVER["REQUEST_METHOD"] === "GET") {
    echo file_get_contents($file);
    exit;
}

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $input = json_decode(file_get_contents("php://input"), true);
    $action = $input["action"] ?? "";
    $data = json_decode(file_get_contents($file), true);

    switch ($action) {
        case "add":
            $data["todo"][] = [
                "id" => uniqid(),
                "text" => htmlspecialchars($input["text"] ?? ""),
                "created" => date("Y-m-d H:i"),
            ];
            break;
        case "move":
            $taskId = $input["taskId"];
            $from = $input["from"];
            $to = $input["to"];
            foreach ($data[$from] as $i => $task) {
                if ($task["id"] === $taskId) {
                    $data[$to][] = $task;
                    array_splice($data[$from], $i, 1);
                    break;
                }
            }
            break;
        case "delete":
            $taskId = $input["taskId"];
            $col = $input["column"];
            $data[$col] = array_values(array_filter($data[$col], fn($t) => $t["id"] !== $taskId));
            break;
    }
    file_put_contents($file, json_encode($data));
    echo json_encode(["ok" => true]);
}
?>

Main Page (index.php)

php
<?php $tasks = json_decode(file_get_contents("data/tasks.json"), true); ?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Kanban To-Do</title>
  <style>
    body { background: #0a0a23; color: #fff; font-family: sans-serif; padding: 2rem; }
    h1 { text-align: center; margin-bottom: 2rem; }
    .board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; max-width: 900px; margin: 0 auto; }
    .column { background: #1a1a3e; border-radius: 16px; padding: 1rem; min-height: 400px; }
    .column h2 { text-align: center; font-size: 1.1rem; margin-bottom: 1rem; padding-bottom: 0.5rem; border-bottom: 2px solid #2d2d5e; }
    .task { background: #2d2d5e; padding: 12px; border-radius: 10px; margin-bottom: 8px; cursor: grab; transition: all 0.2s; }
    .task:hover { transform: translateY(-2px); box-shadow: 0 4px 15px rgba(108,99,255,0.3); }
    .task.dragging { opacity: 0.5; transform: rotate(3deg); }
    .column.over { border: 2px dashed #6c63ff; }
    .add-form { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
    .add-form input { flex: 1; padding: 8px; border-radius: 8px; border: none; background: #2d2d5e; color: #fff; }
    .add-form button { padding: 8px 16px; background: #6c63ff; color: #fff; border: none; border-radius: 8px; cursor: pointer; }
    @keyframes slideIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
    .task { animation: slideIn 0.3s ease; }
  </style>
</head>
<body>
  <h1>Kanban To-Do Board</h1>
  <div class="board">
    <div class="column" data-col="todo" ondragover="e(event)" ondrop="drop(event)">
      <h2>To Do</h2>
      <div class="add-form">
        <input id="newTask" placeholder="New task...">
        <button onclick="addTask()">+</button>
      </div>
      <div class="tasks" id="todo">
        <?php foreach ($tasks["todo"] as $t): ?>
          <div class="task" draggable="true" data-id="<?= $t["id"] ?>"><?= $t["text"] ?></div>
        <?php endforeach; ?>
      </div>
    </div>
    <div class="column" data-col="progress" ondragover="e(event)" ondrop="drop(event)">
      <h2>In Progress</h2>
      <div class="tasks" id="progress">
        <?php foreach ($tasks["progress"] as $t): ?>
          <div class="task" draggable="true" data-id="<?= $t["id"] ?>"><?= $t["text"] ?></div>
        <?php endforeach; ?>
      </div>
    </div>
    <div class="column" data-col="done" ondragover="e(event)" ondrop="drop(event)">
      <h2>Done</h2>
      <div class="tasks" id="done">
        <?php foreach ($tasks["done"] as $t): ?>
          <div class="task" draggable="true" data-id="<?= $t["id"] ?>"><?= $t["text"] ?></div>
        <?php endforeach; ?>
      </div>
    </div>
  </div>
  <script>
  let draggedTask = null, fromCol = null;
  document.querySelectorAll(".task").forEach(initDrag);
  function initDrag(task) {
    task.addEventListener("dragstart", ev => {
      draggedTask = task; fromCol = task.closest(".column").dataset.col;
      task.classList.add("dragging");
    });
    task.addEventListener("dragend", () => task.classList.remove("dragging"));
  }
  function e(ev) { ev.preventDefault(); ev.currentTarget.classList.add("over"); }
  async function drop(ev) {
    ev.preventDefault();
    const col = ev.currentTarget;
    col.classList.remove("over");
    const toCol = col.dataset.col;
    col.querySelector(".tasks").appendChild(draggedTask);
    await fetch("api.php", { method: "POST", headers: {"Content-Type":"application/json"}, body: JSON.stringify({ action:"move", taskId: draggedTask.dataset.id, from: fromCol, to: toCol }) });
  }
  async function addTask() {
    const input = document.getElementById("newTask");
    if (!input.value.trim()) return;
    await fetch("api.php", { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({ action:"add", text: input.value }) });
    location.reload();
  }
  </script>
</body>
</html>

Technologies

- PHP — JSON file persistence, REST API - HTML5 Drag & Drop API — native drag events - CSS — slide-in animations, hover effects - JavaScript — drag handlers, async API calls

Related Projects

Comments (0)

Leave a Comment

No comments yet. Be the first to comment!