Drag on Drop Tausch verbessert
This commit is contained in:
1 parent
01035f0834
commit
e5e0703106
2 files changed
+153
-57
No files matched your search
+149
-52
@@ -276,11 +276,24 @@ class App {
|
|||||||
if (!parentTask) { this.hideContextMenu(); return; }
|
if (!parentTask) { this.hideContextMenu(); return; }
|
||||||
const subtask = this.contextMenuTarget;
|
const subtask = this.contextMenuTarget;
|
||||||
parentTask.subtasks = parentTask.subtasks.filter(st => st.id !== subtask.id);
|
parentTask.subtasks = parentTask.subtasks.filter(st => st.id !== subtask.id);
|
||||||
|
|
||||||
|
// Create new task locally
|
||||||
|
const newTask = new Task(Date.now().toString(), subtask.title, subtask.description, subtask.size, subtask.reward);
|
||||||
|
newTask.dueDate = subtask.dueDate;
|
||||||
|
newTask.color = subtask.color;
|
||||||
|
newTask.completed = subtask.completed;
|
||||||
|
this.tasks.push(newTask);
|
||||||
|
|
||||||
|
this._syncToServer(parentTask);
|
||||||
try {
|
try {
|
||||||
await fetch(`${API_URL}/tasks/${parentTask.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(parentTask) });
|
await fetch(`${API_URL}/tasks`, {
|
||||||
await fetch(`${API_URL}/tasks`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: subtask.title, description: subtask.description, size: subtask.size, reward: subtask.reward, dueDate: subtask.dueDate, color: subtask.color }) });
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||||
await this.loadTasks();
|
body: JSON.stringify({ title: subtask.title, description: subtask.description, size: subtask.size, reward: subtask.reward, dueDate: subtask.dueDate, color: subtask.color })
|
||||||
|
});
|
||||||
} catch (error) { console.error('Error promoting subtask:', error); }
|
} catch (error) { console.error('Error promoting subtask:', error); }
|
||||||
|
|
||||||
|
this.updateOverallProgress();
|
||||||
|
this.render();
|
||||||
this.hideContextMenu();
|
this.hideContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,23 +331,32 @@ class App {
|
|||||||
const subtask = parentTask.subtasks.find(st => st.id === editId);
|
const subtask = parentTask.subtasks.find(st => st.id === editId);
|
||||||
if (subtask) {
|
if (subtask) {
|
||||||
Object.assign(subtask, { title, description, size, reward, expandDescription, dueDate, color });
|
Object.assign(subtask, { title, description, size, reward, expandDescription, dueDate, color });
|
||||||
await this.updateTask(parentTask);
|
this._syncToServer(parentTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const task = taskList.find(t => t.id === editId);
|
const task = taskList.find(t => t.id === editId);
|
||||||
if (task) {
|
if (task) {
|
||||||
Object.assign(task, { title, description, size, reward, expandDescription, dueDate, color });
|
Object.assign(task, { title, description, size, reward, expandDescription, dueDate, color });
|
||||||
await this.updateTask(task);
|
this._syncToServer(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.updateOverallProgress();
|
||||||
|
if (this.viewMode === 'archive') this.renderArchive();
|
||||||
|
else this.render();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_URL}/tasks`, {
|
const response = await fetch(`${API_URL}/tasks`, {
|
||||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ title, description, size, reward, expandDescription, dueDate, color })
|
body: JSON.stringify({ title, description, size, reward, expandDescription, dueDate, color })
|
||||||
});
|
});
|
||||||
if (response.ok) await this.loadTasks();
|
if (response.ok) {
|
||||||
|
const newTaskData = await response.json();
|
||||||
|
const newTask = this._mapTaskData(newTaskData);
|
||||||
|
this.tasks.push(newTask);
|
||||||
|
this.updateOverallProgress();
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
} catch (error) { console.error('Error creating task:', error); }
|
} catch (error) { console.error('Error creating task:', error); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,14 +391,12 @@ class App {
|
|||||||
|
|
||||||
async loadTasks() {
|
async loadTasks() {
|
||||||
try {
|
try {
|
||||||
const prevProgress = this._previousOverallProgress;
|
|
||||||
const response = await fetch(`${API_URL}/tasks`);
|
const response = await fetch(`${API_URL}/tasks`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.tasks = data.map(d => this._mapTaskData(d));
|
this.tasks = data.map(d => this._mapTaskData(d));
|
||||||
this.updateOverallProgress();
|
this.updateOverallProgress();
|
||||||
if (this.viewMode === 'active') this.render();
|
if (this.viewMode === 'active') this.render();
|
||||||
this.loadArchivedCount();
|
this.loadArchivedCount();
|
||||||
if (this._initialized) this._checkCelebrations(prevProgress);
|
|
||||||
this._initialized = true;
|
this._initialized = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading tasks:', error);
|
console.error('Error loading tasks:', error);
|
||||||
@@ -441,72 +461,111 @@ class App {
|
|||||||
document.getElementById('overall-progress-fill').style.width = overallProgress + '%';
|
document.getElementById('overall-progress-fill').style.width = overallProgress + '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Task Actions ───
|
// ─── Server Sync (fire-and-forget) ───
|
||||||
|
|
||||||
async deleteTask(taskId) {
|
_syncToServer(task) {
|
||||||
try {
|
fetch(`${API_URL}/tasks/${task.id}`, {
|
||||||
const response = await fetch(`${API_URL}/tasks/${taskId}`, { method: 'DELETE' });
|
method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(task)
|
||||||
if (response.ok) {
|
}).catch(err => console.error('Sync error:', err));
|
||||||
if (this.viewMode === 'archive') await this.loadArchivedTasks();
|
|
||||||
else await this.loadTasks();
|
|
||||||
}
|
|
||||||
} catch (error) { console.error('Error deleting task:', error); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleTaskComplete(taskId) {
|
_syncDelete(taskId) {
|
||||||
|
fetch(`${API_URL}/tasks/${taskId}`, { method: 'DELETE' })
|
||||||
|
.catch(err => console.error('Sync error:', err));
|
||||||
|
}
|
||||||
|
|
||||||
|
_syncReorder() {
|
||||||
|
fetch(`${API_URL}/tasks/reorder`, {
|
||||||
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(this.tasks.map(t => t.id))
|
||||||
|
}).catch(err => console.error('Sync error:', err));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Task Actions (optimistic) ───
|
||||||
|
|
||||||
|
deleteTask(taskId) {
|
||||||
|
if (this.viewMode === 'archive') {
|
||||||
|
this.archivedTasks = this.archivedTasks.filter(t => t.id !== taskId);
|
||||||
|
this._syncDelete(taskId);
|
||||||
|
this.renderArchive();
|
||||||
|
this.updateArchiveCount();
|
||||||
|
} else {
|
||||||
|
this.tasks = this.tasks.filter(t => t.id !== taskId);
|
||||||
|
this._syncDelete(taskId);
|
||||||
|
this.updateOverallProgress();
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTaskComplete(taskId) {
|
||||||
const task = this.getCurrentTasks().find(t => t.id === taskId);
|
const task = this.getCurrentTasks().find(t => t.id === taskId);
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
|
const prevProgress = this._previousOverallProgress;
|
||||||
const wasCompleted = task.completed || task.calculateProgress() === 100;
|
const wasCompleted = task.completed || task.calculateProgress() === 100;
|
||||||
task.completed = !task.completed;
|
task.completed = !task.completed;
|
||||||
if (task.subtasks.length > 0) task.subtasks.forEach(st => st.completed = task.completed);
|
if (task.subtasks.length > 0) task.subtasks.forEach(st => st.completed = task.completed);
|
||||||
const isNowCompleted = task.completed || task.calculateProgress() === 100;
|
const isNowCompleted = task.completed || task.calculateProgress() === 100;
|
||||||
if (!wasCompleted && isNowCompleted && task.reward) this._celebrateTaskId = taskId;
|
if (!wasCompleted && isNowCompleted && task.reward) this._celebrateTaskId = taskId;
|
||||||
await this.updateTask(task);
|
|
||||||
|
this.updateOverallProgress();
|
||||||
|
this.render();
|
||||||
|
this._checkCelebrations(prevProgress);
|
||||||
|
this._syncToServer(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleSubtaskComplete(taskId, subtaskId) {
|
toggleSubtaskComplete(taskId, subtaskId) {
|
||||||
const task = this.getCurrentTasks().find(t => t.id === taskId);
|
const task = this.getCurrentTasks().find(t => t.id === taskId);
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
const subtask = task.subtasks.find(st => st.id === subtaskId);
|
const subtask = task.subtasks.find(st => st.id === subtaskId);
|
||||||
if (!subtask) return;
|
if (!subtask) return;
|
||||||
|
const prevProgress = this._previousOverallProgress;
|
||||||
const wasSubCompleted = subtask.completed;
|
const wasSubCompleted = subtask.completed;
|
||||||
subtask.completed = !subtask.completed;
|
subtask.completed = !subtask.completed;
|
||||||
if (!wasSubCompleted && subtask.completed && subtask.reward) this._celebrateTaskId = taskId;
|
if (!wasSubCompleted && subtask.completed && subtask.reward) this._celebrateTaskId = taskId;
|
||||||
const parentWillComplete = task.calculateProgress() === 100;
|
const parentWillComplete = task.calculateProgress() === 100;
|
||||||
if (parentWillComplete && task.reward && !task.completed) this._celebrateTaskId = taskId;
|
if (parentWillComplete && task.reward && !task.completed) this._celebrateTaskId = taskId;
|
||||||
await this.updateTask(task);
|
|
||||||
|
this.updateOverallProgress();
|
||||||
|
this.render();
|
||||||
|
this._checkCelebrations(prevProgress);
|
||||||
|
this._syncToServer(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteSubtask(taskId, subtaskId) {
|
deleteSubtask(taskId, subtaskId) {
|
||||||
const task = this.getCurrentTasks().find(t => t.id === taskId);
|
const task = this.getCurrentTasks().find(t => t.id === taskId);
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
task.subtasks = task.subtasks.filter(st => st.id !== subtaskId);
|
task.subtasks = task.subtasks.filter(st => st.id !== subtaskId);
|
||||||
await this.updateTask(task);
|
this.updateOverallProgress();
|
||||||
}
|
this.render();
|
||||||
|
this._syncToServer(task);
|
||||||
async updateTask(task) {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${API_URL}/tasks/${task.id}`, {
|
|
||||||
method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(task)
|
|
||||||
});
|
|
||||||
if (response.ok) {
|
|
||||||
if (this.viewMode === 'archive') await this.loadArchivedTasks();
|
|
||||||
else await this.loadTasks();
|
|
||||||
}
|
|
||||||
} catch (error) { console.error('Error updating task:', error); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async archiveTask(taskId) {
|
async archiveTask(taskId) {
|
||||||
|
// Move from active to archived locally
|
||||||
|
const taskIndex = this.tasks.findIndex(t => t.id === taskId);
|
||||||
|
if (taskIndex === -1) return;
|
||||||
|
const [task] = this.tasks.splice(taskIndex, 1);
|
||||||
|
this.archivedTasks.push(task);
|
||||||
|
this.updateOverallProgress();
|
||||||
|
this.render();
|
||||||
|
this.updateArchiveCount();
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_URL}/tasks/${taskId}/archive`, { method: 'PUT' });
|
await fetch(`${API_URL}/tasks/${taskId}/archive`, { method: 'PUT' });
|
||||||
if (response.ok) { await this.loadTasks(); await this.loadArchivedCount(); }
|
|
||||||
} catch (error) { console.error('Error archiving task:', error); }
|
} catch (error) { console.error('Error archiving task:', error); }
|
||||||
}
|
}
|
||||||
|
|
||||||
async unarchiveTask(taskId) {
|
async unarchiveTask(taskId) {
|
||||||
|
// Move from archived back to active
|
||||||
|
const taskIndex = this.archivedTasks.findIndex(t => t.id === taskId);
|
||||||
|
if (taskIndex === -1) return;
|
||||||
|
const [task] = this.archivedTasks.splice(taskIndex, 1);
|
||||||
|
this.tasks.push(task);
|
||||||
|
this.renderArchive();
|
||||||
|
this.updateArchiveCount();
|
||||||
|
// Also update active progress in background
|
||||||
|
this.updateOverallProgress();
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_URL}/tasks/${taskId}/unarchive`, { method: 'PUT' });
|
await fetch(`${API_URL}/tasks/${taskId}/unarchive`, { method: 'PUT' });
|
||||||
if (response.ok) { await this.loadArchivedTasks(); await this.loadTasks(); }
|
|
||||||
} catch (error) { console.error('Error restoring task:', error); }
|
} catch (error) { console.error('Error restoring task:', error); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,13 +622,18 @@ class App {
|
|||||||
e.preventDefault(); e.stopPropagation(); e.currentTarget.classList.remove('drag-over');
|
e.preventDefault(); e.stopPropagation(); e.currentTarget.classList.remove('drag-over');
|
||||||
if (this.draggedTask && this.draggedTask.id !== targetTask.id) {
|
if (this.draggedTask && this.draggedTask.id !== targetTask.id) {
|
||||||
targetTask.subtasks.push(this.draggedTask);
|
targetTask.subtasks.push(this.draggedTask);
|
||||||
try { await fetch(`${API_URL}/tasks/${this.draggedTask.id}`, { method: 'DELETE' }); await this.updateTask(targetTask); }
|
this.tasks = this.tasks.filter(t => t.id !== this.draggedTask.id);
|
||||||
catch (error) { console.error('Error moving task:', error); }
|
this._syncDelete(this.draggedTask.id);
|
||||||
|
this._syncToServer(targetTask);
|
||||||
|
this.updateOverallProgress();
|
||||||
|
this.render();
|
||||||
} else if (this.draggedSubtask && this.draggedParent && targetTask.id !== this.draggedParent.id) {
|
} else if (this.draggedSubtask && this.draggedParent && targetTask.id !== this.draggedParent.id) {
|
||||||
this.draggedParent.subtasks = this.draggedParent.subtasks.filter(st => st.id !== this.draggedSubtask.id);
|
this.draggedParent.subtasks = this.draggedParent.subtasks.filter(st => st.id !== this.draggedSubtask.id);
|
||||||
targetTask.subtasks.push(this.draggedSubtask);
|
targetTask.subtasks.push(this.draggedSubtask);
|
||||||
try { await this.updateTask(this.draggedParent); await this.updateTask(targetTask); }
|
this._syncToServer(this.draggedParent);
|
||||||
catch (error) { console.error('Error moving subtask:', error); }
|
this._syncToServer(targetTask);
|
||||||
|
this.updateOverallProgress();
|
||||||
|
this.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,22 +642,53 @@ class App {
|
|||||||
if (!this.draggedTask) return;
|
if (!this.draggedTask) return;
|
||||||
const currentIndex = this.tasks.findIndex(t => t.id === this.draggedTask.id);
|
const currentIndex = this.tasks.findIndex(t => t.id === this.draggedTask.id);
|
||||||
if (currentIndex === -1 || currentIndex === targetIndex) return;
|
if (currentIndex === -1 || currentIndex === targetIndex) return;
|
||||||
|
|
||||||
|
// Update data
|
||||||
this.tasks.splice(currentIndex, 1);
|
this.tasks.splice(currentIndex, 1);
|
||||||
this.tasks.splice(targetIndex, 0, this.draggedTask);
|
this.tasks.splice(targetIndex, 0, this.draggedTask);
|
||||||
try {
|
|
||||||
await fetch(`${API_URL}/tasks/reorder`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(this.tasks.map(t => t.id)) });
|
// Swap DOM nodes directly
|
||||||
this.render();
|
const container = document.getElementById('tasks-container');
|
||||||
} catch (error) { console.error('Error reordering:', error); await this.loadTasks(); }
|
const cards = [...container.children];
|
||||||
|
const draggedCard = cards[currentIndex];
|
||||||
|
if (draggedCard) {
|
||||||
|
draggedCard.remove();
|
||||||
|
const referenceCard = container.children[targetIndex];
|
||||||
|
if (referenceCard) container.insertBefore(draggedCard, referenceCard);
|
||||||
|
else container.appendChild(draggedCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync to server in background
|
||||||
|
this._syncReorder();
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleSubtaskReorder(e, parentTask, targetIndex) {
|
async handleSubtaskReorder(e, parentTask, targetIndex) {
|
||||||
e.preventDefault(); e.stopPropagation(); e.currentTarget.classList.remove('drag-over');
|
e.preventDefault(); e.stopPropagation(); e.currentTarget.classList.remove('drag-over');
|
||||||
if (!this.draggedSubtask || !this.draggedParent || this.draggedParent.id !== parentTask.id) return;
|
if (!this.draggedSubtask || !this.draggedParent || this.draggedParent.id !== parentTask.id) return;
|
||||||
if (this.draggedSubtaskIndex === targetIndex) return;
|
if (this.draggedSubtaskIndex === targetIndex) return;
|
||||||
|
|
||||||
|
// Update data
|
||||||
const subtask = parentTask.subtasks[this.draggedSubtaskIndex];
|
const subtask = parentTask.subtasks[this.draggedSubtaskIndex];
|
||||||
parentTask.subtasks.splice(this.draggedSubtaskIndex, 1);
|
parentTask.subtasks.splice(this.draggedSubtaskIndex, 1);
|
||||||
parentTask.subtasks.splice(targetIndex, 0, subtask);
|
parentTask.subtasks.splice(targetIndex, 0, subtask);
|
||||||
await this.updateTask(parentTask);
|
|
||||||
|
// Swap subtask DOM nodes
|
||||||
|
const card = document.querySelector(`[data-task-id="${parentTask.id}"]`);
|
||||||
|
if (card) {
|
||||||
|
const subtaskContainer = card.querySelector('.subtasks-container');
|
||||||
|
if (subtaskContainer) {
|
||||||
|
const subtaskNodes = [...subtaskContainer.children];
|
||||||
|
const draggedNode = subtaskNodes[this.draggedSubtaskIndex];
|
||||||
|
if (draggedNode) {
|
||||||
|
draggedNode.remove();
|
||||||
|
const ref = subtaskContainer.children[targetIndex];
|
||||||
|
if (ref) subtaskContainer.insertBefore(draggedNode, ref);
|
||||||
|
else subtaskContainer.appendChild(draggedNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._syncToServer(parentTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Render: Active ───
|
// ─── Render: Active ───
|
||||||
@@ -735,12 +830,13 @@ class App {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const container = document.getElementById('tasks-container');
|
const container = document.getElementById('tasks-container');
|
||||||
container.innerHTML = '';
|
|
||||||
if (this.tasks.length === 0) {
|
if (this.tasks.length === 0) {
|
||||||
container.innerHTML = `<div class="empty-state"><h2>No goals yet</h2><p>Click "+ New Goal" to get started</p></div>`;
|
container.innerHTML = `<div class="empty-state"><h2>No goals yet</h2><p>Click "+ New Goal" to get started</p></div>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.tasks.forEach((task, index) => container.appendChild(this.renderTask(task, index)));
|
const fragment = document.createDocumentFragment();
|
||||||
|
this.tasks.forEach((task, index) => fragment.appendChild(this.renderTask(task, index)));
|
||||||
|
container.replaceChildren(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Render: Archive ───
|
// ─── Render: Archive ───
|
||||||
@@ -830,12 +926,13 @@ class App {
|
|||||||
|
|
||||||
renderArchive() {
|
renderArchive() {
|
||||||
const container = document.getElementById('tasks-container');
|
const container = document.getElementById('tasks-container');
|
||||||
container.innerHTML = '';
|
|
||||||
if (this.archivedTasks.length === 0) {
|
if (this.archivedTasks.length === 0) {
|
||||||
container.innerHTML = `<div class="empty-state"><h2>Archive is empty</h2><p>Completed tasks you archive will appear here</p></div>`;
|
container.innerHTML = `<div class="empty-state"><h2>Archive is empty</h2><p>Completed tasks you archive will appear here</p></div>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.archivedTasks.forEach(task => container.appendChild(this.renderArchivedTask(task)));
|
const fragment = document.createDocumentFragment();
|
||||||
|
this.archivedTasks.forEach(task => fragment.appendChild(this.renderArchivedTask(task)));
|
||||||
|
container.replaceChildren(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Celebrations ───
|
// ─── Celebrations ───
|
||||||
|
|||||||
+4
-5
@@ -9,8 +9,8 @@
|
|||||||
--card-border: rgba(255, 255, 255, 0.45);
|
--card-border: rgba(255, 255, 255, 0.45);
|
||||||
--card-hover: rgba(255, 255, 255, 0.7);
|
--card-hover: rgba(255, 255, 255, 0.7);
|
||||||
--card-shadow: 0 2px 12px rgba(60, 60, 120, 0.1);
|
--card-shadow: 0 2px 12px rgba(60, 60, 120, 0.1);
|
||||||
--subtask-bg: rgba(255, 255, 255, 0.25);
|
--subtask-bg: rgba(255, 255, 255, 0.14);
|
||||||
--subtask-border: rgba(255, 255, 255, 0.2);
|
--subtask-border: rgba(255, 255, 255, 0.12);
|
||||||
|
|
||||||
--text-primary: #1e293b;
|
--text-primary: #1e293b;
|
||||||
--text-secondary: #475569;
|
--text-secondary: #475569;
|
||||||
@@ -491,7 +491,6 @@ button {
|
|||||||
border: 1px solid var(--card-border);
|
border: 1px solid var(--card-border);
|
||||||
border-left: 4px solid var(--accent);
|
border-left: 4px solid var(--accent);
|
||||||
position: relative;
|
position: relative;
|
||||||
animation: cardIn 0.25s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-card:hover {
|
.task-card:hover {
|
||||||
@@ -728,8 +727,8 @@ button {
|
|||||||
.subtask:last-child { margin-bottom: 0; }
|
.subtask:last-child { margin-bottom: 0; }
|
||||||
|
|
||||||
.subtask:hover {
|
.subtask:hover {
|
||||||
background: rgba(255, 255, 255, 0.4);
|
background: rgba(255, 255, 255, 0.28);
|
||||||
border-color: rgba(99, 102, 241, 0.25);
|
border-color: rgba(99, 102, 241, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask:active { cursor: grabbing; }
|
.subtask:active { cursor: grabbing; }
|
||||||
|
|||||||
Reference in new issue
Block a user