first pass at cmd+shift+left to pull subtask out

Hunter
Friday, June 27th, 2025 at 12:19 AM

index.html+64 

index.html
 894  							applyShakeAnimation(task.id);
 895  						}
 896  					}
 897 +				} else if (e.key === 'ArrowLeft' && e.shiftKey && (e.metaKey || e.ctrlKey)) {
 898 +					e.preventDefault();
 899 +					pullSubtaskOutLayer(task);
 900  				} else if (e.key === 'ArrowLeft' && e.shiftKey) {
 901  					e.preventDefault();
 902  					if (!keyHandler.shiftLeft.pressed) {

 966  				scheduleSave();
 967  			}
 968  
 969 +			function pullSubtaskOutLayer(subtask) {
 970 +				// Don't allow pulling the current parent task
 971 +				if (subtask === currentTask) {
 972 +					return;
 973 +				}
 974 +
 975 +				// Don't allow pulling when at root level
 976 +				if (taskPath.length <= 1) {
 977 +					return;
 978 +				}
 979 +
 980 +				const currentParent = findParentTask(subtask);
 981 +				if (!currentParent) return;
 982 +
 983 +				// Find the grandparent (the outer layer we're pulling into)
 984 +				const grandParent = findGrandParentTask(currentParent);
 985 +				if (!grandParent) return;
 986 +
 987 +				// Remove the subtask from its current parent
 988 +				const currentIndex = currentParent.subtasks.findIndex(t => t.id === subtask.id);
 989 +				if (currentIndex === -1) return;
 990 +				currentParent.subtasks.splice(currentIndex, 1);
 991 +
 992 +				// Find where to insert in the grandparent's subtasks
 993 +				const currentParentIndex = grandParent.subtasks.findIndex(t => t.id === currentParent.id);
 994 +				if (currentParentIndex === -1) {
 995 +					// Fallback: add to end of grandparent's subtasks
 996 +					grandParent.subtasks.push(subtask);
 997 +				} else {
 998 +					// Insert after the current parent's position
 999 +					grandParent.subtasks.splice(currentParentIndex + 1, 0, subtask);
1000 +				}
1001 +
1002 +				// Update task states
1003 +				updateTaskAndAncestors(currentParent);
1004 +				updateTaskAndAncestors(grandParent);
1005 +
1006 +				// Navigate to the outer layer (grandparent level)
1007 +				taskPath.pop(); // Remove current level
1008 +				currentTask = taskPath[taskPath.length - 1]; // Set to grandparent
1009 +
1010 +				// Re-render the view
1011 +				renderCurrentView();
1012 +
1013 +				// Focus on the moved subtask in its new location
1014 +				selectAndFocusTask(subtask);
1015 +
1016 +				scheduleSave();
1017 +			}
1018 +
1019 +			function findGrandParentTask(parentTask) {
1020 +				// Find the grandparent of the given parent task
1021 +				for (let i = taskPath.length - 1; i >= 0; i--) {
1022 +					const potentialGrandParent = taskPath[i];
1023 +					if (potentialGrandParent.subtasks.some(t => t.id === parentTask.id)) {
1024 +						return potentialGrandParent;
1025 +					}
1026 +				}
1027 +				return null;
1028 +			}
1029 +
1030  			function addNewSubtask(parentTask, currentSubtask = null) {
1031  				const newSubtask = { id: Date.now(), text: '', state: 0, subtasks: [], selectedSubtaskId: null };
1032  				if (currentSubtask) {