diff --git a/public/app.js b/public/app.js index e525968..de1cdc2 100644 --- a/public/app.js +++ b/public/app.js @@ -121,9 +121,30 @@ class App { promoteOption.style.display = 'none'; } - contextMenu.style.left = e.pageX + 'px'; - contextMenu.style.top = e.pageY + 'px'; + // Use clientX/clientY for fixed positioning (viewport-relative) + let x = e.clientX; + let y = e.clientY; + + // Temporarily show offscreen to measure dimensions + contextMenu.style.left = '-9999px'; + contextMenu.style.top = '-9999px'; contextMenu.classList.add('show'); + + const menuWidth = contextMenu.offsetWidth; + const menuHeight = contextMenu.offsetHeight; + + // Clamp to viewport boundaries + if (x + menuWidth > window.innerWidth) { + x = window.innerWidth - menuWidth - 5; + } + if (y + menuHeight > window.innerHeight) { + y = window.innerHeight - menuHeight - 5; + } + if (x < 0) x = 5; + if (y < 0) y = 5; + + contextMenu.style.left = x + 'px'; + contextMenu.style.top = y + 'px'; } hideContextMenu() { @@ -546,10 +567,19 @@ class App { ${task.completed ? 'Undo' : 'Complete'} - ${task.subtasks.length > 0 ? this.renderSubtasks(task) : ''} -
Drop tasks here to add as subtasks
`; + // Append subtasks as DOM nodes to preserve event listeners + if (task.subtasks.length > 0) { + card.appendChild(this.renderSubtasks(task)); + } + + // Add drop zone + const dropZone = document.createElement('div'); + dropZone.className = 'drop-zone'; + dropZone.textContent = 'Drop tasks here to add as subtasks'; + card.appendChild(dropZone); + return card; } @@ -623,7 +653,7 @@ class App { container.appendChild(div); }); - return container.outerHTML; + return container; } render() { diff --git a/readme.me b/readme.me new file mode 100644 index 0000000..8d17e78 --- /dev/null +++ b/readme.me @@ -0,0 +1,95 @@ +# Learning Progress Tracker + +A web-based goal and learning progress tracker with subtask management, drag-and-drop reordering, and persistent server-side storage. + +## Features + +- **Goal Management** — Create, edit, and delete learning goals with titles, descriptions, sizes, and optional rewards. +- **Subtasks** — Break goals into smaller subtasks. Drag any task onto another to nest it as a subtask, or promote subtasks back to top-level goals. +- **Progress Tracking** — Automatic progress calculation based on subtask completion, weighted by task size (Small 10%, Medium 25%, Large 50%). +- **Drag & Drop** — Reorder tasks and subtasks via drag-and-drop. Hold over a task to reveal its drop zone for nesting. +- **Context Menus** — Right-click any task or subtask to edit, delete, or promote (subtasks only). +- **Rewards** — Set optional rewards on goals that are revealed only upon completion. +- **Persistent Storage** — All data is stored in a SQLite database on the server. +- **Dark Theme** — Clean, modern dark UI. + +## Project Structure + +``` +├── public/ +│ ├── index.html # Main HTML page +│ ├── styles.css # Stylesheet (dark theme) +│ └── app.js # Client-side application logic +├── server/ +│ └── server.js # Express server with SQLite backend +├── data/ # SQLite database (auto-created) +├── package.json +├── dockerfile +└── README.md +``` + +## Getting Started + +### Prerequisites + +- [Node.js](https://nodejs.org/) v18 or later +- npm (comes with Node.js) + +### Installation + +```bash +# Clone or download the project +cd learning-progress-tracker + +# Install dependencies +npm install + +# Start the server +npm start +``` + +The app will be available at **http://localhost:3000**. + +For development with auto-reload: + +```bash +npm run dev +``` + +### Docker + +```bash +# Build the image +docker build -t learning-tracker . + +# Run the container (persists data via volume) +docker run -d -p 3000:3000 -v tracker-data:/app/data learning-tracker +``` + +## API Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `GET` | `/api/tasks` | Fetch all tasks | +| `POST` | `/api/tasks` | Create a new task | +| `PUT` | `/api/tasks/:id` | Update a task (including subtasks) | +| `DELETE` | `/api/tasks/:id` | Delete a task | +| `POST` | `/api/tasks/reorder` | Reorder tasks (accepts array of task IDs) | + +## Usage + +- Click **+ New Goal** to create a task. +- **Right-click** a task or subtask for edit/delete/promote options. +- **Drag** tasks to reorder them, or hold over another task to nest it as a subtask. +- Mark tasks complete to reveal rewards and track overall progress. + +## Tech Stack + +- **Frontend:** Vanilla JavaScript, HTML, CSS +- **Backend:** Node.js, Express +- **Database:** SQLite3 +- **Containerization:** Docker + +## License + +MIT \ No newline at end of file