Last active
October 19, 2025 06:22
-
-
Save Mazyod/f40ab3859772f27beb6ea2b319e0e530 to your computer and use it in GitHub Desktop.
TODO HTA App
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <HTML> | |
| <HEAD> | |
| <HTA:APPLICATION | |
| ID="TodoApp" | |
| APPLICATIONNAME="Work TODO Manager" | |
| BORDER="dialog" | |
| BORDERSTYLE="normal" | |
| CAPTION="yes" | |
| ICON="" | |
| MAXIMIZEBUTTON="yes" | |
| MINIMIZEBUTTON="yes" | |
| SHOWINTASKBAR="yes" | |
| SINGLEINSTANCE="yes" | |
| SYSMENU="yes" | |
| WINDOWSTATE="normal" | |
| /> | |
| <meta http-equiv="x-ua-compatible" content="ie=9" /> | |
| <TITLE>Work TODO Manager</TITLE> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: #667eea; | |
| padding: 20px; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| max-width: 800px; | |
| margin: 0 auto; | |
| background: white; | |
| border-radius: 12px; | |
| box-shadow: 0 10px 40px rgba(0,0,0,0.2); | |
| overflow: hidden; | |
| } | |
| .header { | |
| background: #667eea; | |
| color: white; | |
| padding: 30px; | |
| text-align: center; | |
| } | |
| .header h1 { | |
| font-size: 28px; | |
| margin-bottom: 5px; | |
| } | |
| .header p { | |
| opacity: 0.9; | |
| font-size: 14px; | |
| } | |
| .input-section { | |
| padding: 25px; | |
| background: #f8f9fa; | |
| border-bottom: 1px solid #dee2e6; | |
| } | |
| .input-group { | |
| margin-bottom: 15px; | |
| } | |
| #todoInput { | |
| width: 70%; | |
| padding: 12px 15px; | |
| border: 2px solid #dee2e6; | |
| border-radius: 6px; | |
| font-size: 14px; | |
| } | |
| #todoInput:focus { | |
| outline: none; | |
| border-color: #667eea; | |
| } | |
| .btn { | |
| padding: 12px 24px; | |
| border: none; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 14px; | |
| font-weight: 600; | |
| margin-left: 10px; | |
| } | |
| .btn-primary { | |
| background: #667eea; | |
| color: white; | |
| } | |
| .btn-primary:hover { | |
| background: #5568d3; | |
| } | |
| .btn-secondary { | |
| background: #6c757d; | |
| color: white; | |
| } | |
| .btn-secondary:hover { | |
| background: #5a6268; | |
| } | |
| .btn-danger { | |
| background: #dc3545; | |
| color: white; | |
| padding: 6px 12px; | |
| font-size: 12px; | |
| } | |
| .btn-danger:hover { | |
| background: #c82333; | |
| } | |
| .priority-group { | |
| margin-top: 10px; | |
| } | |
| .priority-group label { | |
| font-size: 13px; | |
| color: #495057; | |
| font-weight: 600; | |
| margin-right: 10px; | |
| } | |
| .priority-btn { | |
| padding: 8px 16px; | |
| border: 2px solid #dee2e6; | |
| background: white; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 12px; | |
| margin-right: 5px; | |
| } | |
| .priority-btn.active { | |
| border-color: #667eea; | |
| background: #667eea; | |
| color: white; | |
| } | |
| .filters { | |
| padding: 15px 25px; | |
| background: white; | |
| border-bottom: 1px solid #dee2e6; | |
| } | |
| .filter-btn { | |
| padding: 8px 16px; | |
| border: 1px solid #dee2e6; | |
| background: white; | |
| border-radius: 20px; | |
| cursor: pointer; | |
| font-size: 13px; | |
| margin-right: 5px; | |
| } | |
| .filter-btn.active { | |
| background: #667eea; | |
| color: white; | |
| border-color: #667eea; | |
| } | |
| .stats { | |
| padding: 15px 25px; | |
| background: #f8f9fa; | |
| font-size: 13px; | |
| color: #6c757d; | |
| } | |
| .todo-list { | |
| padding: 0; | |
| max-height: 500px; | |
| overflow-y: auto; | |
| } | |
| .todo-item { | |
| padding: 18px 25px; | |
| border-bottom: 1px solid #dee2e6; | |
| } | |
| .todo-item:hover { | |
| background: #f8f9fa; | |
| } | |
| .todo-item.completed { | |
| opacity: 0.6; | |
| } | |
| .todo-checkbox { | |
| width: 20px; | |
| height: 20px; | |
| cursor: pointer; | |
| vertical-align: middle; | |
| margin-right: 15px; | |
| } | |
| .todo-text { | |
| font-size: 15px; | |
| color: #212529; | |
| display: inline; | |
| } | |
| .todo-item.completed .todo-text { | |
| text-decoration: line-through; | |
| color: #6c757d; | |
| } | |
| .todo-meta { | |
| font-size: 12px; | |
| color: #6c757d; | |
| margin-top: 5px; | |
| } | |
| .priority-badge { | |
| display: inline-block; | |
| padding: 3px 10px; | |
| border-radius: 12px; | |
| font-size: 11px; | |
| font-weight: 600; | |
| margin-right: 8px; | |
| } | |
| .priority-high { | |
| background: #ffe5e5; | |
| color: #dc3545; | |
| } | |
| .priority-medium { | |
| background: #fff3cd; | |
| color: #856404; | |
| } | |
| .priority-low { | |
| background: #d1ecf1; | |
| color: #0c5460; | |
| } | |
| .empty-state { | |
| padding: 60px 25px; | |
| text-align: center; | |
| color: #6c757d; | |
| } | |
| .delete-btn-container { | |
| float: right; | |
| } | |
| </style> | |
| </HEAD> | |
| <BODY> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1>Work TODO Manager</h1> | |
| <p>Stay organized and productive</p> | |
| </div> | |
| <div class="input-section"> | |
| <div class="input-group"> | |
| <input type="text" id="todoInput" placeholder="What needs to be done?" /> | |
| <button class="btn btn-primary" onclick="addTodo()">Add Task</button> | |
| </div> | |
| <div class="priority-group"> | |
| <label>Priority:</label> | |
| <button class="priority-btn" data-priority="low" onclick="setPriority('low')">Low</button> | |
| <button class="priority-btn active" data-priority="medium" onclick="setPriority('medium')">Medium</button> | |
| <button class="priority-btn" data-priority="high" onclick="setPriority('high')">High</button> | |
| </div> | |
| </div> | |
| <div class="filters"> | |
| <button class="filter-btn active" onclick="filterTodos('all')">All</button> | |
| <button class="filter-btn" onclick="filterTodos('active')">Active</button> | |
| <button class="filter-btn" onclick="filterTodos('completed')">Completed</button> | |
| <button class="filter-btn" onclick="filterTodos('high')">High Priority</button> | |
| <button class="btn btn-secondary" onclick="clearCompleted()">Clear Completed</button> | |
| </div> | |
| <div class="stats"> | |
| <span id="stats"></span> | |
| </div> | |
| <div class="todo-list" id="todoList"> | |
| <div class="empty-state"> | |
| <p>No tasks yet. Add one above to get started!</p> | |
| </div> | |
| </div> | |
| </div> | |
| <script type="text/javascript"> | |
| var todos = []; | |
| var currentPriority = 'medium'; | |
| var currentFilter = 'all'; | |
| var fso = new ActiveXObject("Scripting.FileSystemObject"); | |
| var shell = new ActiveXObject("WScript.Shell"); | |
| var dataFile = shell.ExpandEnvironmentStrings("%TEMP%") + "\\WorkTodos.json"; | |
| // Load todos from file on startup | |
| function loadTodos() { | |
| try { | |
| if (fso.FileExists(dataFile)) { | |
| var file = fso.OpenTextFile(dataFile, 1); | |
| var content = file.ReadAll(); | |
| file.Close(); | |
| if (content) { | |
| todos = JSON.parse(content); | |
| } | |
| } | |
| } catch (e) { | |
| // File doesn't exist or error reading, start fresh | |
| todos = []; | |
| } | |
| renderTodos(); | |
| } | |
| // Save todos to file | |
| function saveTodos() { | |
| try { | |
| var file = fso.CreateTextFile(dataFile, true); | |
| file.Write(JSON.stringify(todos)); | |
| file.Close(); | |
| } catch (e) { | |
| alert("Error saving todos: " + e.message); | |
| } | |
| } | |
| // Set priority | |
| function setPriority(priority) { | |
| currentPriority = priority; | |
| var buttons = document.querySelectorAll('.priority-btn'); | |
| for (var i = 0; i < buttons.length; i++) { | |
| var btn = buttons[i]; | |
| if (btn.getAttribute('data-priority') === priority) { | |
| btn.className = 'priority-btn active'; | |
| } else { | |
| btn.className = 'priority-btn'; | |
| } | |
| } | |
| } | |
| // Add new todo | |
| function addTodo() { | |
| var input = document.getElementById('todoInput'); | |
| var text = input.value; | |
| // Trim whitespace | |
| text = text.replace(/^\s+|\s+$/g, ''); | |
| if (text === '') { | |
| return; | |
| } | |
| var todo = { | |
| id: new Date().getTime(), | |
| text: text, | |
| completed: false, | |
| priority: currentPriority, | |
| createdAt: new Date().toISOString() | |
| }; | |
| todos.unshift(todo); | |
| saveTodos(); | |
| renderTodos(); | |
| input.value = ''; | |
| input.focus(); | |
| } | |
| // Toggle todo completion | |
| function toggleTodo(id) { | |
| for (var i = 0; i < todos.length; i++) { | |
| if (todos[i].id === id) { | |
| todos[i].completed = !todos[i].completed; | |
| break; | |
| } | |
| } | |
| saveTodos(); | |
| renderTodos(); | |
| } | |
| // Delete todo | |
| function deleteTodo(id) { | |
| var newTodos = []; | |
| for (var i = 0; i < todos.length; i++) { | |
| if (todos[i].id !== id) { | |
| newTodos.push(todos[i]); | |
| } | |
| } | |
| todos = newTodos; | |
| saveTodos(); | |
| renderTodos(); | |
| } | |
| // Filter todos | |
| function filterTodos(filter) { | |
| currentFilter = filter; | |
| var buttons = document.querySelectorAll('.filter-btn'); | |
| for (var i = 0; i < buttons.length; i++) { | |
| buttons[i].className = 'filter-btn'; | |
| } | |
| event.srcElement.className = 'filter-btn active'; | |
| renderTodos(); | |
| } | |
| // Clear completed todos | |
| function clearCompleted() { | |
| var newTodos = []; | |
| for (var i = 0; i < todos.length; i++) { | |
| if (!todos[i].completed) { | |
| newTodos.push(todos[i]); | |
| } | |
| } | |
| todos = newTodos; | |
| saveTodos(); | |
| renderTodos(); | |
| } | |
| // Get filtered todos | |
| function getFilteredTodos() { | |
| var filtered = []; | |
| for (var i = 0; i < todos.length; i++) { | |
| var todo = todos[i]; | |
| var include = false; | |
| if (currentFilter === 'all') { | |
| include = true; | |
| } else if (currentFilter === 'active') { | |
| include = !todo.completed; | |
| } else if (currentFilter === 'completed') { | |
| include = todo.completed; | |
| } else if (currentFilter === 'high') { | |
| include = todo.priority === 'high'; | |
| } | |
| if (include) { | |
| filtered.push(todo); | |
| } | |
| } | |
| return filtered; | |
| } | |
| // Render todos | |
| function renderTodos() { | |
| var listElement = document.getElementById('todoList'); | |
| var filtered = getFilteredTodos(); | |
| // Update stats | |
| var total = todos.length; | |
| var active = 0; | |
| var completed = 0; | |
| for (var i = 0; i < todos.length; i++) { | |
| if (todos[i].completed) { | |
| completed++; | |
| } else { | |
| active++; | |
| } | |
| } | |
| var statsText = total + ' task' + (total !== 1 ? 's' : '') + ' | ' + | |
| active + ' active | ' + | |
| completed + ' completed'; | |
| document.getElementById('stats').innerHTML = statsText; | |
| if (filtered.length === 0) { | |
| var emptyMsg = todos.length === 0 ? | |
| 'No tasks yet. Add one above to get started!' : | |
| 'No tasks match this filter.'; | |
| listElement.innerHTML = '<div class="empty-state"><p>' + emptyMsg + '</p></div>'; | |
| return; | |
| } | |
| var html = ''; | |
| for (var i = 0; i < filtered.length; i++) { | |
| var todo = filtered[i]; | |
| var date = new Date(todo.createdAt); | |
| var dateStr = date.toLocaleDateString() + ' ' + | |
| date.getHours() + ':' + | |
| (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); | |
| var completedClass = todo.completed ? ' completed' : ''; | |
| var checked = todo.completed ? ' checked' : ''; | |
| html += '<div class="todo-item' + completedClass + '">'; | |
| html += '<input type="checkbox" class="todo-checkbox"' + checked + ' onchange="toggleTodo(' + todo.id + ')" />'; | |
| html += '<div style="display:inline-block; width: 70%;">'; | |
| html += '<div class="todo-text">' + escapeHtml(todo.text) + '</div>'; | |
| html += '<div class="todo-meta">'; | |
| html += '<span class="priority-badge priority-' + todo.priority + '">' + todo.priority.toUpperCase() + '</span>'; | |
| html += '<span>' + dateStr + '</span>'; | |
| html += '</div>'; | |
| html += '</div>'; | |
| html += '<div class="delete-btn-container">'; | |
| html += '<button class="btn btn-danger" onclick="deleteTodo(' + todo.id + ')">Delete</button>'; | |
| html += '</div>'; | |
| html += '<div style="clear:both;"></div>'; | |
| html += '</div>'; | |
| } | |
| listElement.innerHTML = html; | |
| } | |
| // Escape HTML to prevent issues | |
| function escapeHtml(text) { | |
| var div = document.createElement('div'); | |
| div.appendChild(document.createTextNode(text)); | |
| return div.innerHTML; | |
| } | |
| // Handle Enter key in input | |
| function setupEnterKey() { | |
| var input = document.getElementById('todoInput'); | |
| input.onkeypress = function(e) { | |
| e = e || window.event; | |
| var keyCode = e.keyCode || e.which; | |
| if (keyCode === 13) { | |
| addTodo(); | |
| return false; | |
| } | |
| }; | |
| } | |
| // Initialize on load | |
| window.onload = function() { | |
| window.resizeTo(850, 700); | |
| loadTodos(); | |
| setupEnterKey(); | |
| }; | |
| </script> | |
| </BODY> | |
| </HTML> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment