mytodo / index.html
fredmo's picture
Update index.html
72d8c68 verified
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My To-Do List</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: #f4f4f9;
color: #333;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh; /* Changed to min-height for longer lists */
margin: 0;
padding: 20px 0; /* Add some padding for scrollable content */
}
#app-container {
background: #fff;
padding: 25px 40px;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 500px; /* Increased max-width slightly for more buttons */
box-sizing: border-box;
}
h1 {
color: #444;
text-align: center;
margin-top: 0;
margin-bottom: 20px;
font-weight: 600;
}
#task-input-container {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
#task-input {
flex-grow: 1;
padding: 12px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
}
#add-task-btn {
padding: 12px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
font-weight: 500;
transition: background-color 0.3s;
}
#add-task-btn:hover {
background-color: #0056b3;
}
#task-list {
list-style: none;
padding: 0;
margin: 0;
}
.task-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 0; /* Adjusted padding, horizontal padding now on children */
border-bottom: 1px solid #eee;
font-size: 16px;
}
.task-item:last-child {
border-bottom: none;
}
.task-text-content { /* New class for the text part */
cursor: pointer;
flex-grow: 1;
padding-right: 10px; /* Space before action buttons */
overflow-wrap: break-word; /* Prevent long text from breaking layout */
word-break: break-word;
}
.task-item.completed .task-text-content { /* Updated selector */
text-decoration: line-through;
color: #aaa;
}
.task-actions {
display: flex;
align-items: center;
flex-shrink: 0; /* Prevent actions container from shrinking */
}
.emoji-toggle {
background: transparent;
border: 1px solid transparent; /* Keep layout consistent */
border-radius: 4px;
padding: 4px 6px;
cursor: pointer;
margin-left: 5px;
font-size: 18px; /* Slightly larger for emojis */
opacity: 0.4; /* Dimmed when inactive */
transition: opacity 0.2s, border-color 0.2s;
line-height: 1; /* Ensure consistent height */
}
.emoji-toggle:hover {
opacity: 0.7;
}
.emoji-toggle.active {
opacity: 1;
border: 1px solid #007bff;
}
.delete-btn {
background: #dc3545;
color: white;
border: none;
border-radius: 50%;
width: 28px;
height: 28px;
cursor: pointer;
font-size: 16px;
line-height: 28px;
text-align: center;
transition: background-color 0.3s;
margin-left: 8px; /* Space from emoji toggles */
flex-shrink: 0;
}
.delete-btn:hover {
background: #c82333;
}
</style>
</head>
<body>
<div id="app-container">
<h1>To-Do List βœ…</h1>
<div id="task-input-container">
<input type="text" id="task-input" placeholder="Add a new task...">
<button id="add-task-btn">Add</button>
</div>
<ul id="task-list"></ul>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const taskInput = document.getElementById('task-input');
const addTaskBtn = document.getElementById('add-task-btn');
const taskList = document.getElementById('task-list');
const initialRawTasks = [
{ text: "Write the Unit Test", completed: true },
{ text: "Check the PR", completed: true },
{ text: "Debug the GPU trace", completed: true }
];
// Helper function to ensure task objects have all necessary properties
const ensureTaskProperties = (task) => {
return {
text: task.text,
completed: !!task.completed,
isCode: !!task.isCode,
isAdmin: !!task.isAdmin,
isClient: !!task.isClient,
};
};
// Load tasks from local storage or use initial tasks if storage is empty
let tasks = [];
const storedTasks = localStorage.getItem('tasks');
if (storedTasks) {
tasks = JSON.parse(storedTasks).map(ensureTaskProperties);
} else {
tasks = initialRawTasks.map(ensureTaskProperties);
}
if (tasks.length === 0 && initialRawTasks.length > 0 && !storedTasks) { // Ensure initial tasks are used if local storage was empty
tasks = initialRawTasks.map(ensureTaskProperties);
}
// Function to save tasks to local storage
const saveTasks = () => {
localStorage.setItem('tasks', JSON.stringify(tasks));
};
// Function to render tasks to the DOM
const renderTasks = () => {
// Sort tasks: Client first, then Code, then by completion status
tasks.sort((a, b) => {
// Client tasks come first
if (a.isClient && !b.isClient) return -1;
if (!a.isClient && b.isClient) return 1;
// If both are Client or both are not Client, then Code tasks
if (a.isCode && !b.isCode) return -1;
if (!a.isCode && b.isCode) return 1;
// If same client and code status, then uncompleted tasks first
if (!a.completed && b.completed) return -1;
if (a.completed && !b.completed) return 1;
return 0; // Maintain relative order for items with same priority
});
taskList.innerHTML = ''; // Clear existing list
tasks.forEach((task, index) => {
const li = document.createElement('li');
li.className = 'task-item';
if (task.completed) {
li.classList.add('completed');
}
// Task text content (emojis + text)
const taskTextContentEl = document.createElement('span');
taskTextContentEl.className = 'task-text-content';
let emojisPrefix = '';
if (task.isClient) emojisPrefix += 'πŸ‘€ ';
if (task.isCode) emojisPrefix += 'πŸ’» ';
if (task.isAdmin) emojisPrefix += 'βš™οΈ ';
taskTextContentEl.textContent = emojisPrefix + task.text;
taskTextContentEl.addEventListener('click', () => toggleTaskCompletion(index));
// Actions container (toggles + delete)
const actionsContainer = document.createElement('div');
actionsContainer.className = 'task-actions';
// Emoji Toggles
const categories = [
{ type: 'client', emoji: 'πŸ‘€', prop: 'isClient', title: 'Client Task' },
{ type: 'code', emoji: 'πŸ’»', prop: 'isCode', title: 'Code Task' },
{ type: 'admin', emoji: 'βš™οΈ', prop: 'isAdmin', title: 'Admin Task' }
];
categories.forEach(cat => {
const toggleBtn = document.createElement('button');
toggleBtn.className = 'emoji-toggle';
toggleBtn.textContent = cat.emoji;
toggleBtn.title = `Toggle ${cat.title}`;
toggleBtn.dataset.type = cat.type;
if (task[cat.prop]) {
toggleBtn.classList.add('active');
}
toggleBtn.addEventListener('click', (e) => {
e.stopPropagation(); // Prevent task completion toggle
toggleEmojiCategory(index, cat.prop);
});
actionsContainer.appendChild(toggleBtn);
});
// Delete button
const deleteBtn = document.createElement('button');
deleteBtn.textContent = 'Γ—';
deleteBtn.className = 'delete-btn';
deleteBtn.title = "Delete Task";
deleteBtn.addEventListener('click', (e) => {
e.stopPropagation(); // Prevent task completion toggle
deleteTask(index);
});
actionsContainer.appendChild(deleteBtn);
li.appendChild(taskTextContentEl);
li.appendChild(actionsContainer);
taskList.appendChild(li);
});
};
// Function to add a new task
const addTask = () => {
const taskText = taskInput.value.trim();
if (taskText !== '') {
// Add new task with default false for emoji categories
tasks.unshift(ensureTaskProperties({ text: taskText, completed: false }));
taskInput.value = '';
saveTasks();
renderTasks();
}
};
// Function to delete a task
const deleteTask = (index) => {
tasks.splice(index, 1);
saveTasks();
renderTasks();
};
// Function to toggle a task's completion status
const toggleTaskCompletion = (index) => {
tasks[index].completed = !tasks[index].completed;
saveTasks();
renderTasks(); // Re-render to apply style and potentially re-sort if completion affects order
};
// Function to toggle an emoji category for a task
const toggleEmojiCategory = (index, categoryProp) => {
tasks[index][categoryProp] = !tasks[index][categoryProp];
saveTasks();
renderTasks(); // Re-render to update emojis, sort, and toggle style
};
// Event listener for the "Add" button
addTaskBtn.addEventListener('click', addTask);
// Event listener for the Enter key in the input field
taskInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addTask();
}
});
// Initial render of tasks on page load
renderTasks();
});
</script>
</body>
</html>