{% extends "base.html" %}
{% block title %}
{% if task %}Task #{{ task.id }}: {{ task.name }}{% else %}Track WebUI{% endif %}
{% endblock %}
{% block toolbar_buttons %}
{% if task %}
<button class="toolbar-btn" onclick="toggleViewMode()" id="mode-toggle-btn">
<span id="mode-icon">👁️</span> <span id="mode-label">Overview</span>
</button>
{% endif %}
{{ super() }}
{% endblock %}
{% block content %}
{% if task %}
<header class="task-header">
<h1>{{ task.name }}{% if task.alias %} <span class="task-alias">({{ task.alias }})</span>{% endif %}</h1>
<div class="task-meta">
{% if task.ticket_id %}
<span class="badge">{{ task.ticket_id }}</span>
{% else %}
<span class="task-id">Task #{{ task.id }}</span>
{% endif %}
</div>
</header>
<div id="overview-section">
{% if task.is_today_task %}
<div class="two-pane-layout">
{% include "partials/calendar.html" %}
{% include "partials/links.html" %}
</div>
{% else %}
<div class="two-pane-layout">
{% include "partials/description.html" %}
{% include "partials/ticket.html" %}
</div>
<div class="two-pane-layout">
{% include "partials/repos.html" %}
{% include "partials/links.html" %}
</div>
{% endif %}
</div>
<div class="two-pane-layout main-content">
{% include "partials/todo_list.html" %}
{% include "partials/scrap_list.html" %}
</div>
{% else %}
<div class="no-task">
<div class="icon">📋</div>
<h2>No Active Task</h2>
<p>Create a new task or switch to an existing one to get started.</p>
<p style="margin-top: 1rem;">
Run <code>track new "Task name"</code> to create a new task.
</p>
</div>
{% endif %}
<script>
function scrollToOldestPendingTask() {
document.querySelectorAll('.todo-item').forEach(item => {
item.classList.remove('oldest-pending');
});
const firstPendingTodo = document.querySelector('.todo-item.pending');
if (firstPendingTodo) {
firstPendingTodo.classList.add('oldest-pending');
const listContainer = document.querySelector('#todos-section .list-container');
if (listContainer) {
const todoRect = firstPendingTodo.getBoundingClientRect();
const containerRect = listContainer.getBoundingClientRect();
const scrollOffset = todoRect.top - containerRect.top + listContainer.scrollTop;
listContainer.scrollTo({
top: scrollOffset,
behavior: 'smooth'
});
}
}
}
function toggleViewMode() {
const section = document.getElementById('overview-section');
const icon = document.getElementById('mode-icon');
const label = document.getElementById('mode-label');
const body = document.body;
if (section.style.display === 'none') {
section.style.display = 'block';
icon.textContent = '👁️';
label.textContent = 'Overview';
body.classList.remove('focus-mode');
localStorage.setItem('viewMode', 'overview');
document.querySelectorAll('.todo-item').forEach(item => {
item.classList.remove('oldest-pending');
});
} else {
section.style.display = 'none';
icon.textContent = '🎯';
label.textContent = 'Focus';
body.classList.add('focus-mode');
localStorage.setItem('viewMode', 'focus');
setTimeout(scrollToOldestPendingTask, 100);
}
}
function restoreViewMode() {
const viewMode = localStorage.getItem('viewMode') || 'overview';
const section = document.getElementById('overview-section');
const icon = document.getElementById('mode-icon');
const label = document.getElementById('mode-label');
const body = document.body;
if (viewMode === 'focus') {
if (section && icon && label) {
section.style.display = 'none';
icon.textContent = '🎯';
label.textContent = 'Focus';
body.classList.add('focus-mode');
setTimeout(scrollToOldestPendingTask, 100);
}
} else {
if (section && icon && label) {
section.style.display = 'block';
icon.textContent = '👁️';
label.textContent = 'Overview';
body.classList.remove('focus-mode');
document.querySelectorAll('.todo-item').forEach(item => {
item.classList.remove('oldest-pending');
});
}
}
}
document.addEventListener('DOMContentLoaded', restoreViewMode);
document.body.addEventListener('htmx:afterSwap', restoreViewMode);
document.body.addEventListener('htmx:afterSettle', restoreViewMode);
function scrollToRelatedScraps(event, todoId) {
event.stopPropagation();
const scrapItems = document.querySelectorAll('.scrap-item');
if (scrapItems.length === 0) {
console.log('No scraps found');
return;
}
scrapItems.forEach(item => item.classList.remove('scrap-highlighted'));
let foundScraps = [];
scrapItems.forEach(item => {
const activeTodoId = item.getAttribute('data-active-todo-id');
if (activeTodoId && parseInt(activeTodoId) === todoId) {
foundScraps.push(item);
}
});
if (foundScraps.length === 0) {
console.log(`No scraps found for todo #${todoId}`);
const statusText = document.querySelector('#connection-status .status-text');
if (statusText) {
const originalText = statusText.textContent;
statusText.textContent = `No scraps for todo #${todoId}`;
setTimeout(() => {
statusText.textContent = originalText;
}, 2000);
}
return;
}
const targetScrap = foundScraps[0];
targetScrap.classList.add('scrap-highlighted');
const listContainer = document.querySelector('#scraps-section .list-container');
if (listContainer) {
const scrapRect = targetScrap.getBoundingClientRect();
const containerRect = listContainer.getBoundingClientRect();
const scrollOffset = scrapRect.top - containerRect.top + listContainer.scrollTop;
listContainer.scrollTo({
top: scrollOffset - 20, behavior: 'smooth'
});
}
setTimeout(() => {
targetScrap.classList.remove('scrap-highlighted');
}, 3500);
console.log(`Found ${foundScraps.length} scrap(s) for todo #${todoId}`);
}
</script>
{% endblock %}