taskmaster-kr / script.js
gihakkk's picture
제일 위에 달력도 있어서 표시되면 좋겠어. 해야할 일, 내용 이렇게 두 개 넣을 수 있으면 좋겠어
b1e8890 verified
document.addEventListener('DOMContentLoaded', function() {
// Load Korean locale for Flatpickr
flatpickr.localize(flatpickr.l10ns.ko);
// DOM Elements
const taskForm = document.getElementById('task-form');
const taskTitle = document.getElementById('task-title');
const taskDescription = document.getElementById('task-description');
const taskList = document.getElementById('task-list');
const taskCount = document.getElementById('task-count');
const clearCompletedBtn = document.getElementById('clear-completed');
const filterButtons = document.querySelectorAll('.filter-btn');
const dateInput = document.createElement('input');
dateInput.type = 'text';
dateInput.className = 'date-input px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500';
dateInput.placeholder = '마감일 선택';
taskForm.insertBefore(dateInput, taskForm.lastElementChild);
// Initialize Flatpickr for Korean
flatpickr(dateInput, {
locale: "ko",
dateFormat: "Y-m-d",
minDate: "today",
allowInput: true
});
// State
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
let currentFilter = 'all';
// Initialize
renderTasks();
updateTaskCount();
// Event Listeners
taskForm.addEventListener('submit', addTask);
clearCompletedBtn.addEventListener('click', clearCompletedTasks);
filterButtons.forEach(btn => btn.addEventListener('click', filterTasks));
// Functions
function addTask(e) {
e.preventDefault();
const title = taskTitle.value.trim();
const description = taskDescription.value.trim();
if (title) {
const newTask = {
id: Date.now(),
title: title,
description: description,
completed: false,
createdAt: new Date().toISOString(),
dueDate: dateInput.value || null
};
dateInput.value = ''; // Reset date input after adding task
tasks.push(newTask);
saveTasks();
renderTasks();
updateTaskCount();
taskTitle.value = '';
taskDescription.value = '';
}
}
function renderTasks() {
taskList.innerHTML = '';
if (tasks.length === 0) {
taskList.innerHTML = '<li class="p-4 text-center text-gray-500">할 일이 없습니다. 위에서 추가해보세요!</li>';
return;
}
let filteredTasks = tasks;
if (currentFilter === 'active') {
filteredTasks = tasks.filter(task => !task.completed);
} else if (currentFilter === 'completed') {
filteredTasks = tasks.filter(task => task.completed);
}
if (filteredTasks.length === 0) {
let message = '';
if (currentFilter === 'active') {
message = '진행중인 할 일이 없습니다!';
} else if (currentFilter === 'completed') {
message = '완료된 할 일이 없습니다!';
} else {
message = '할 일이 없습니다. 위에서 추가해보세요!';
}
taskList.innerHTML = `<li class="p-4 text-center text-gray-500">${message}</li>`;
return;
}
filteredTasks.forEach(task => {
const taskItem = document.createElement('li');
taskItem.className = `task-item p-4 flex items-center ${task.completed ? 'completed' : ''}`;
taskItem.dataset.id = task.id;
taskItem.draggable = true;
taskItem.innerHTML = `
<div class="flex items-center flex-1">
<input
type="checkbox"
class="mr-3 h-5 w-5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 cursor-pointer"
${task.completed ? 'checked' : ''}
>
<div class="flex-1">
<div class="task-title font-medium">${task.title}</div>
${task.description ? `<div class="task-description text-sm text-gray-500 mt-1">${task.description}</div>` : ''}
</div>
${task.dueDate ? `<span class="due-date ml-2 text-xs px-2 py-1 bg-indigo-100 text-indigo-800 rounded-full">${formatDueDate(task.dueDate)}</span>` : ''}
<input
type="text"
class="edit-input hidden flex-1 px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-indigo-500"
value="${task.title}"
>
</div>
<div class="flex gap-2">
<button class="edit-btn p-1 text-gray-500 hover:text-indigo-600">
<i data-feather="edit-2" class="w-4 h-4"></i>
</button>
<button class="delete-btn p-1 text-gray-500 hover:text-red-600">
<i data-feather="trash-2" class="w-4 h-4"></i>
</button>
</div>
`;
taskList.appendChild(taskItem);
// Add event listeners to the new elements
const checkbox = taskItem.querySelector('input[type="checkbox"]');
const editBtn = taskItem.querySelector('.edit-btn');
const deleteBtn = taskItem.querySelector('.delete-btn');
const taskText = taskItem.querySelector('.task-text');
const editInput = taskItem.querySelector('.edit-input');
checkbox.addEventListener('change', () => toggleTaskComplete(task.id));
deleteBtn.addEventListener('click', () => deleteTask(task.id));
editBtn.addEventListener('click', () => {
taskItem.classList.add('editing');
taskText.classList.add('hidden');
editInput.classList.remove('hidden');
editInput.focus();
});
editInput.addEventListener('blur', () => saveEdit(task.id, editInput));
editInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
saveEdit(task.id, editInput);
}
});
// Drag and drop events
taskItem.addEventListener('dragstart', handleDragStart);
taskItem.addEventListener('dragover', handleDragOver);
taskItem.addEventListener('drop', handleDrop);
taskItem.addEventListener('dragend', handleDragEnd);
});
feather.replace();
}
function toggleTaskComplete(id) {
tasks = tasks.map(task =>
task.id === id ? {...task, completed: !task.completed} : task
);
saveTasks();
renderTasks();
updateTaskCount();
}
function deleteTask(id) {
tasks = tasks.filter(task => task.id !== id);
saveTasks();
renderTasks();
updateTaskCount();
}
function saveEdit(id, inputElement) {
const newText = inputElement.value.trim();
if (newText) {
tasks = tasks.map(task =>
task.id === id ? {...task, text: newText} : task
);
saveTasks();
renderTasks();
} else {
renderTasks();
}
}
function clearCompletedTasks() {
tasks = tasks.filter(task => !task.completed);
saveTasks();
renderTasks();
updateTaskCount();
}
function filterTasks(e) {
currentFilter = e.target.dataset.filter;
filterButtons.forEach(btn => {
btn.classList.remove('active');
if (btn.dataset.filter === currentFilter) {
btn.classList.add('active');
}
});
renderTasks();
}
function updateTaskCount() {
const activeTasks = tasks.filter(task => !task.completed).length;
taskCount.textContent = activeTasks;
}
function saveTasks() {
localStorage.setItem('tasks', JSON.stringify(tasks));
}
function formatDueDate(dateString) {
if (!dateString) return '';
const date = new Date(dateString);
const now = new Date();
const diffTime = date - now;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
if (diffDays === 0) return '오늘 마감';
if (diffDays === 1) return '내일 마감';
if (diffDays < 0) return `${Math.abs(diffDays)}일 지남`;
return `${diffDays}일 남음`;
}
// Render calendar with tasks
function renderCalendarTasks() {
const calendar = document.querySelector('custom-calendar');
if (calendar) {
// Implement logic to highlight dates with tasks
// This would require querying your tasks array for dates
}
}
// Drag and Drop Functions
let draggedItem = null;
function handleDragStart(e) {
draggedItem = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
this.classList.add('dragging');
}
function handleDragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
}
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
if (draggedItem !== this) {
const draggedId = parseInt(draggedItem.dataset.id);
const targetId = parseInt(this.dataset.id);
// Find indexes
const draggedIndex = tasks.findIndex(task => task.id === draggedId);
const targetIndex = tasks.findIndex(task => task.id === targetId);
// Reorder array
const [removed] = tasks.splice(draggedIndex, 1);
tasks.splice(targetIndex, 0, removed);
saveTasks();
renderTasks();
}
}
function handleDragEnd() {
this.classList.remove('dragging');
}
});