Spaces:
Running
Running
Download index.html from marinhows/task-tracker-pro: direct link, hf CLI and curl.
- Browser
- Download file 22.1 kB
-
https://huggingface.co/spaces/marinhows/task-tracker-pro/resolve/main/index.html
- Command line
-
hf download hf://spaces/marinhows/task-tracker-pro/index.html
-
curl -L -o index.html https://huggingface.co/spaces/marinhows/task-tracker-pro/resolve/main/index.html
22.1 kB
| <html lang="pt-BR"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Task Tracker Pro</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: { | |
| 50: '#f0f9ff', | |
| 100: '#e0f2fe', | |
| 200: '#bae6fd', | |
| 300: '#7dd3fc', | |
| 400: '#38bdf8', | |
| 500: '#0ea5e9', | |
| 600: '#0284c7', | |
| 700: '#0369a1', | |
| 800: '#075985', | |
| 900: '#0c4a6e', | |
| }, | |
| secondary: { | |
| 50: '#fdf2f8', | |
| 100: '#fce7f3', | |
| 200: '#fbcfe8', | |
| 300: '#f9a8d4', | |
| 400: '#f472b6', | |
| 500: '#ec4899', | |
| 600: '#db2777', | |
| 700: '#be185d', | |
| 800: '#9d174d', | |
| 900: '#831843', | |
| } | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <header class="mb-12 text-center"> | |
| <h1 class="text-4xl font-bold text-primary-700 mb-2">Task Tracker Pro ✨</h1> | |
| <p class="text-gray-600">Organize suas tarefas diárias e semanais</p> | |
| </header> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> | |
| <!-- Daily Tasks Section --> | |
| <section class="bg-white rounded-xl shadow-lg p-6"> | |
| <div class="flex items-center justify-between mb-6"> | |
| <h2 class="text-2xl font-bold text-gray-800 flex items-center"> | |
| <i data-feather="sun" class="mr-2 text-primary-500"></i> | |
| Tarefas Diárias | |
| </h2> | |
| <button id="addDailyTaskBtn" class="bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg flex items-center transition duration-300"> | |
| <i data-feather="plus-circle" class="mr-1"></i> | |
| Nova Tarefa | |
| </button> | |
| </div> | |
| <!-- Add Daily Task Form --> | |
| <div id="dailyTaskForm" class="mb-6 hidden"> | |
| <div class="bg-blue-50 rounded-lg p-4 border border-blue-200"> | |
| <input type="text" id="dailyTaskInput" placeholder="Digite sua nova tarefa..." class="w-full p-3 rounded-lg border border-gray-300 mb-3 focus:outline-none focus:ring-2 focus:ring-primary-300"> | |
| <input type="text" id="dailyAssigneeInput" placeholder="Responsável pela tarefa..." class="w-full p-3 rounded-lg border border-gray-300 mb-3 focus:outline-none focus:ring-2 focus:ring-primary-300"> | |
| <div class="flex justify-end space-x-2"> | |
| <button id="cancelDailyTaskBtn" class="px-4 py-2 text-gray-600 hover:text-gray-800 transition">Cancelar</button> | |
| <button id="saveDailyTaskBtn" class="bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg transition duration-300">Adicionar</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Daily Task List --> | |
| <div id="dailyTaskList" class="space-y-3"> | |
| <!-- Tasks will be added here dynamically --> | |
| </div> | |
| <!-- Empty State --> | |
| <div id="emptyDailyTaskState" class="hidden text-center py-12"> | |
| <i data-feather="check-circle" class="mx-auto text-gray-300 mb-4" style="width: 64px; height: 64px;"></i> | |
| <h3 class="text-xl font-medium text-gray-500 mb-2">Nenhuma tarefa diária</h3> | |
| <p class="text-gray-400">Adicione tarefas para hoje!</p> | |
| </div> | |
| </section> | |
| <!-- Weekly Tasks Section --> | |
| <section class="bg-white rounded-xl shadow-lg p-6"> | |
| <div class="flex items-center justify-between mb-6"> | |
| <h2 class="text-2xl font-bold text-gray-800 flex items-center"> | |
| <i data-feather="calendar" class="mr-2 text-secondary-500"></i> | |
| Tarefas Semanais | |
| </h2> | |
| <button id="addWeeklyTaskBtn" class="bg-secondary-500 hover:bg-secondary-600 text-white px-4 py-2 rounded-lg flex items-center transition duration-300"> | |
| <i data-feather="plus-circle" class="mr-1"></i> | |
| Nova Tarefa | |
| </button> | |
| </div> | |
| <!-- Add Weekly Task Form --> | |
| <div id="weeklyTaskForm" class="mb-6 hidden"> | |
| <div class="bg-purple-50 rounded-lg p-4 border border-purple-200"> | |
| <input type="text" id="weeklyTaskInput" placeholder="Digite sua nova tarefa..." class="w-full p-3 rounded-lg border border-gray-300 mb-3 focus:outline-none focus:ring-2 focus:ring-secondary-300"> | |
| <input type="text" id="weeklyAssigneeInput" placeholder="Responsável pela tarefa..." class="w-full p-3 rounded-lg border border-gray-300 mb-3 focus:outline-none focus:ring-2 focus:ring-secondary-300"> | |
| <div class="flex justify-end space-x-2"> | |
| <button id="cancelWeeklyTaskBtn" class="px-4 py-2 text-gray-600 hover:text-gray-800 transition">Cancelar</button> | |
| <button id="saveWeeklyTaskBtn" class="bg-secondary-500 hover:bg-secondary-600 text-white px-4 py-2 rounded-lg transition duration-300">Adicionar</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Weekly Task List --> | |
| <div id="weeklyTaskList" class="space-y-3"> | |
| <!-- Tasks will be added here dynamically --> | |
| </div> | |
| <!-- Empty State --> | |
| <div id="emptyWeeklyTaskState" class="hidden text-center py-12"> | |
| <i data-feather="check-circle" class="mx-auto text-gray-300 mb-4" style="width: 64px; height: 64px;"></i> | |
| <h3 class="text-xl font-medium text-gray-500 mb-2">Nenhuma tarefa semanal</h3> | |
| <p class="text-gray-400">Adicione tarefas para esta semana!</p> | |
| </div> | |
| </section> | |
| <!-- Task List --> | |
| <div id="taskList" class="space-y-3"> | |
| <!-- Tasks will be added here dynamically --> | |
| <div class="task-item bg-gray-50 p-4 rounded-lg border border-gray-200 flex justify-between items-center"> | |
| <div class="flex items-center"> | |
| <input type="checkbox" class="mr-3 h-5 w-5 text-primary-500 rounded focus:ring-primary-400"> | |
| <span class="task-text">Finalizar relatório mensal</span> | |
| </div> | |
| <button class="delete-task text-gray-400 hover:text-red-500"> | |
| <i data-feather="trash-2"></i> | |
| </button> | |
| </div> | |
| <div class="task-item bg-gray-50 p-4 rounded-lg border border-gray-200 flex justify-between items-center"> | |
| <div class="flex items-center"> | |
| <input type="checkbox" class="mr-3 h-5 w-5 text-primary-500 rounded focus:ring-primary-400" checked> | |
| <span class="task-text line-through text-gray-500">Reunião com equipe de desenvolvimento</span> | |
| </div> | |
| <button class="delete-task text-gray-400 hover:text-red-500"> | |
| <i data-feather="trash-2"></i> | |
| </button> | |
| </div> | |
| <div class="task-item bg-gray-50 p-4 rounded-lg border border-gray-200 flex justify-between items-center"> | |
| <div class="flex items-center"> | |
| <input type="checkbox" class="mr-3 h-5 w-5 text-primary-500 rounded focus:ring-primary-400"> | |
| <span class="task-text">Preparar apresentação para cliente</span> | |
| </div> | |
| <button class="delete-task text-gray-400 hover:text-red-500"> | |
| <i data-feather="trash-2"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Empty State --> | |
| <div id="emptyTaskState" class="hidden text-center py-12"> | |
| <i data-feather="check-circle" class="mx-auto text-gray-300 mb-4" style="width: 64px; height: 64px;"></i> | |
| <h3 class="text-xl font-medium text-gray-500 mb-2">Nenhuma tarefa pendente</h3> | |
| <p class="text-gray-400">Você completou todas as suas tarefas!</p> | |
| </div> | |
| </section> | |
| <!-- History Section --> | |
| <section class="bg-white rounded-xl shadow-lg p-6"> | |
| <div class="flex items-center justify-between mb-6"> | |
| <h2 class="text-2xl font-bold text-gray-800 flex items-center"> | |
| <i data-feather="clock" class="mr-2 text-green-500"></i> | |
| Histórico (7 dias) | |
| </h2> | |
| <button id="clearHistoryBtn" class="text-sm bg-green-500 hover:bg-green-600 text-white px-3 py-1 rounded-lg flex items-center transition duration-300"> | |
| <i data-feather="trash-2" class="mr-1"></i> | |
| Limpar | |
| </button> | |
| </div> | |
| <!-- History List --> | |
| <div id="historyList" class="space-y-3 max-h-[500px] overflow-y-auto pr-2"> | |
| <!-- History items will be added here dynamically --> | |
| </div> | |
| <!-- Empty History State --> | |
| <div id="emptyHistoryState" class="hidden text-center py-12"> | |
| <i data-feather="file-text" class="mx-auto text-gray-300 mb-4" style="width: 64px; height: 64px;"></i> | |
| <h3 class="text-xl font-medium text-gray-500 mb-2">Histórico vazio</h3> | |
| <p class="text-gray-400">Suas tarefas concluídas aparecerão aqui</p> | |
| </div> | |
| </section> | |
| </div> | |
| </div> | |
| <script> | |
| // Initialize Feather Icons | |
| feather.replace(); | |
| // DOM Elements - Daily Tasks | |
| const addDailyTaskBtn = document.getElementById('addDailyTaskBtn'); | |
| const dailyTaskForm = document.getElementById('dailyTaskForm'); | |
| const cancelDailyTaskBtn = document.getElementById('cancelDailyTaskBtn'); | |
| const saveDailyTaskBtn = document.getElementById('saveDailyTaskBtn'); | |
| const dailyTaskInput = document.getElementById('dailyTaskInput'); | |
| const dailyAssigneeInput = document.getElementById('dailyAssigneeInput'); | |
| const dailyTaskList = document.getElementById('dailyTaskList'); | |
| // DOM Elements - Weekly Tasks | |
| const addWeeklyTaskBtn = document.getElementById('addWeeklyTaskBtn'); | |
| const weeklyTaskForm = document.getElementById('weeklyTaskForm'); | |
| const cancelWeeklyTaskBtn = document.getElementById('cancelWeeklyTaskBtn'); | |
| const saveWeeklyTaskBtn = document.getElementById('saveWeeklyTaskBtn'); | |
| const weeklyTaskInput = document.getElementById('weeklyTaskInput'); | |
| const weeklyAssigneeInput = document.getElementById('weeklyAssigneeInput'); | |
| const weeklyTaskList = document.getElementById('weeklyTaskList'); | |
| // DOM Elements - History | |
| const historyList = document.getElementById('historyList'); | |
| const clearHistoryBtn = document.getElementById('clearHistoryBtn'); | |
| // DOM Elements - Empty States | |
| const emptyDailyTaskState = document.getElementById('emptyDailyTaskState'); | |
| const emptyWeeklyTaskState = document.getElementById('emptyWeeklyTaskState'); | |
| const emptyHistoryState = document.getElementById('emptyHistoryState'); | |
| // Data storage | |
| let tasks = JSON.parse(localStorage.getItem('tasks')) || { | |
| daily: [], | |
| weekly: [], | |
| history: [] | |
| }; | |
| // Initialize the app | |
| function init() { | |
| renderTasks(); | |
| updateEmptyStates(); | |
| setupEventListeners(); | |
| } | |
| // Set up event listeners | |
| function setupEventListeners() { | |
| // Daily Tasks | |
| addDailyTaskBtn.addEventListener('click', () => { | |
| dailyTaskForm.classList.toggle('hidden'); | |
| dailyTaskInput.focus(); | |
| }); | |
| cancelDailyTaskBtn.addEventListener('click', () => { | |
| dailyTaskForm.classList.add('hidden'); | |
| dailyTaskInput.value = ''; | |
| dailyAssigneeInput.value = ''; | |
| }); | |
| saveDailyTaskBtn.addEventListener('click', saveDailyTask); | |
| // Weekly Tasks | |
| addWeeklyTaskBtn.addEventListener('click', () => { | |
| weeklyTaskForm.classList.toggle('hidden'); | |
| weeklyTaskInput.focus(); | |
| }); | |
| cancelWeeklyTaskBtn.addEventListener('click', () => { | |
| weeklyTaskForm.classList.add('hidden'); | |
| weeklyTaskInput.value = ''; | |
| weeklyAssigneeInput.value = ''; | |
| }); | |
| saveWeeklyTaskBtn.addEventListener('click', saveWeeklyTask); | |
| // History | |
| clearHistoryBtn.addEventListener('click', clearHistory); | |
| } | |
| // Save daily task | |
| function saveDailyTask() { | |
| const taskText = dailyTaskInput.value.trim(); | |
| const assignee = dailyAssigneeInput.value.trim(); | |
| if (taskText) { | |
| const task = { | |
| id: Date.now(), | |
| text: taskText, | |
| assignee: assignee || 'Não atribuído', | |
| completed: false, | |
| createdAt: new Date().toISOString() | |
| }; | |
| tasks.daily.push(task); | |
| saveTasks(); | |
| renderTasks(); | |
| dailyTaskInput.value = ''; | |
| dailyAssigneeInput.value = ''; | |
| dailyTaskForm.classList.add('hidden'); | |
| updateEmptyStates(); | |
| } | |
| } | |
| // Save weekly task | |
| function saveWeeklyTask() { | |
| const taskText = weeklyTaskInput.value.trim(); | |
| const assignee = weeklyAssigneeInput.value.trim(); | |
| if (taskText) { | |
| const task = { | |
| id: Date.now(), | |
| text: taskText, | |
| assignee: assignee || 'Não atribuído', | |
| completed: false, | |
| createdAt: new Date().toISOString() | |
| }; | |
| tasks.weekly.push(task); | |
| saveTasks(); | |
| renderTasks(); | |
| weeklyTaskInput.value = ''; | |
| weeklyAssigneeInput.value = ''; | |
| weeklyTaskForm.classList.add('hidden'); | |
| updateEmptyStates(); | |
| } | |
| } | |
| // Render all tasks | |
| function renderTasks() { | |
| renderDailyTasks(); | |
| renderWeeklyTasks(); | |
| renderHistory(); | |
| } | |
| // Render daily tasks | |
| function renderDailyTasks() { | |
| dailyTaskList.innerHTML = ''; | |
| tasks.daily.forEach(task => { | |
| const taskElement = createTaskElement(task, 'daily'); | |
| dailyTaskList.appendChild(taskElement); | |
| }); | |
| } | |
| // Render weekly tasks | |
| function renderWeeklyTasks() { | |
| weeklyTaskList.innerHTML = ''; | |
| tasks.weekly.forEach(task => { | |
| const taskElement = createTaskElement(task, 'weekly'); | |
| weeklyTaskList.appendChild(taskElement); | |
| }); | |
| } | |
| // Create task element | |
| function createTaskElement(task, type) { | |
| const taskElement = document.createElement('div'); | |
| taskElement.className = 'task-item bg-gray-50 p-4 rounded-lg border border-gray-200 flex justify-between items-center'; | |
| taskElement.innerHTML = ` | |
| <div class="flex items-center"> | |
| <input type="checkbox" ${task.completed ? 'checked' : ''} class="mr-3 h-5 w-5 text-${type === 'daily' ? 'primary' : 'secondary'}-500 rounded focus:ring-${type === 'daily' ? 'primary' : 'secondary'}-400"> | |
| <div> | |
| <span class="task-text ${task.completed ? 'line-through text-gray-500' : 'text-gray-800'}">${task.text}</span> | |
| <p class="text-xs text-gray-500 mt-1">${task.assignee}</p> | |
| </div> | |
| </div> | |
| <button class="delete-task text-gray-400 hover:text-red-500"> | |
| <i data-feather="trash-2"></i> | |
| </button> | |
| `; | |
| // Add event listeners | |
| const checkbox = taskElement.querySelector('input[type="checkbox"]'); | |
| const deleteBtn = taskElement.querySelector('.delete-task'); | |
| checkbox.addEventListener('change', (e) => toggleTaskCompletion(task.id, type, e.target.checked)); | |
| deleteBtn.addEventListener('click', () => deleteTask(task.id, type)); | |
| feather.replace(); | |
| return taskElement; | |
| } | |
| // Toggle task completion | |
| function toggleTaskCompletion taskId, type, completed) { | |
| const taskList = type === 'daily' ? tasks.daily : tasks.weekly; | |
| const task = taskList.find(t => t.id === taskId); | |
| if (task) { | |
| task.completed = completed; | |
| // If completing task, add to history | |
| if (completed) { | |
| const historyItem = { | |
| ...task, | |
| completedAt: new Date().toISOString() | |
| }; | |
| tasks.history.unshift(historyItem); | |
| // Keep only last 7 days of history | |
| const sevenDaysAgo = new Date(); | |
| sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7); | |
| tasks.history = tasks.history.filter(item => | |
| new Date(item.completedAt) > sevenDaysAgo | |
| ); | |
| } | |
| saveTasks(); | |
| renderTasks(); | |
| updateEmptyStates(); | |
| } | |
| } | |
| // Delete task | |
| function deleteTask(taskId, type) { | |
| if (type === 'daily') { | |
| tasks.daily = tasks.daily.filter(task => task.id !== taskId); | |
| } else { | |
| tasks.weekly = tasks.weekly.filter(task => task.id !== taskId); | |
| } | |
| saveTasks(); | |
| renderTasks(); | |
| updateEmptyStates(); | |
| } | |
| // Render history | |
| function renderHistory() { | |
| historyList.innerHTML = ''; | |
| tasks.history.forEach(item => { | |
| const historyElement = document.createElement('div'); | |
| historyElement.className = 'history-item bg-gray-50 p-4 rounded-lg border border-gray-200'; | |
| const completedDate = new Date(item.completedAt); | |
| const dateStr = completedDate.toLocaleDateString('pt-BR', { | |
| day: 'numeric', | |
| month: 'long' | |
| }); | |
| const timeStr = completedDate.toLocaleTimeString('pt-BR', { | |
| hour: '2-digit', | |
| minute: '2-digit' | |
| }); | |
| historyElement.innerHTML = ` | |
| <div class="flex justify-between items-start"> | |
| <div> | |
| <p class="font-medium text-gray-800">${item.text}</p> | |
| <p class="text-xs text-gray-500 mt-1">${item.assignee}</p> | |
| <p class="text-sm text-gray-500 mt-1">Completada em ${dateStr} às ${timeStr}</p> | |
| </div> | |
| <span class="bg-green-100 text-green-800 text-xs px-2 py-1 rounded-full">Concluída</span> | |
| </div> | |
| `; | |
| historyList.appendChild(historyElement); | |
| }); | |
| } | |
| // Clear history | |
| function clearHistory() { | |
| if (confirm('Tem certeza que deseja limpar todo o histórico?')) { | |
| tasks.history = []; | |
| saveTasks(); | |
| renderTasks(); | |
| updateEmptyStates(); | |
| } | |
| } | |
| // Update empty states | |
| function updateEmptyStates() { | |
| emptyDailyTaskState.classList.toggle('hidden', tasks.daily.length > 0); | |
| emptyWeeklyTaskState.classList.toggle('hidden', tasks.weekly.length > 0); | |
| emptyHistoryState.classList.toggle('hidden', tasks.history.length > 0); | |
| } | |
| // Save tasks to localStorage | |
| function saveTasks() { | |
| localStorage.setItem('tasks', JSON.stringify(tasks)); | |
| } | |
| // Initialize the app | |
| init(); | |
| </script> | |
| </body> | |
| </html> | |