Internal
Public Access
Initial commit: KeepItGoing task management server
Features: - Django-based REST API with web interface - Task management with tags, priorities, and due dates - Time tracking with start/stop timers - Subtasks support - Task filtering (all, today, upcoming, overdue, completed) - Tag-based organization with color coding - Sorting by due date and priority - Auto-assign tags when filtering - Responsive 3-pane layout (sidebar, task list, detail panel) - Task sharing between users - Mobile-responsive design with dark mode support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* KeepItGoing - Main JavaScript
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize components
|
||||
initTimerDisplay();
|
||||
initTaskToggle();
|
||||
initConfirmDialogs();
|
||||
});
|
||||
|
||||
/**
|
||||
* Update timer display
|
||||
*/
|
||||
function initTimerDisplay() {
|
||||
const timerDisplay = document.querySelector('.timer-display');
|
||||
if (!timerDisplay) return;
|
||||
|
||||
const startedAt = new Date(timerDisplay.dataset.started);
|
||||
|
||||
function updateTimer() {
|
||||
const now = new Date();
|
||||
const diff = Math.floor((now - startedAt) / 1000);
|
||||
const hours = Math.floor(diff / 3600).toString().padStart(2, '0');
|
||||
const minutes = Math.floor((diff % 3600) / 60).toString().padStart(2, '0');
|
||||
const seconds = (diff % 60).toString().padStart(2, '0');
|
||||
timerDisplay.textContent = `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
updateTimer();
|
||||
setInterval(updateTimer, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle task toggle without page reload (optional enhancement)
|
||||
*/
|
||||
function initTaskToggle() {
|
||||
// For now, we let the form submit normally
|
||||
// This could be enhanced with AJAX in the future
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize confirmation dialogs
|
||||
*/
|
||||
function initConfirmDialogs() {
|
||||
const deleteButtons = document.querySelectorAll('[data-confirm]');
|
||||
deleteButtons.forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
const message = this.dataset.confirm || 'Are you sure?';
|
||||
if (!confirm(message)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Format duration in seconds to human-readable string
|
||||
*/
|
||||
function formatDuration(seconds) {
|
||||
if (seconds < 60) {
|
||||
return `${seconds}s`;
|
||||
} else if (seconds < 3600) {
|
||||
const mins = Math.floor(seconds / 60);
|
||||
return `${mins}m`;
|
||||
} else {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const mins = Math.floor((seconds % 3600) / 60);
|
||||
return `${hours}h ${mins}m`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date to relative string (today, tomorrow, etc.)
|
||||
*/
|
||||
function formatRelativeDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
const tomorrow = new Date(today);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
const yesterday = new Date(today);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
const dateOnly = new Date(date);
|
||||
dateOnly.setHours(0, 0, 0, 0);
|
||||
|
||||
if (dateOnly.getTime() === today.getTime()) {
|
||||
return 'Today';
|
||||
} else if (dateOnly.getTime() === tomorrow.getTime()) {
|
||||
return 'Tomorrow';
|
||||
} else if (dateOnly.getTime() === yesterday.getTime()) {
|
||||
return 'Yesterday';
|
||||
} else {
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user