Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', function() { | |
| // Initialize feather icons | |
| feather.replace(); | |
| // Command panel toggle | |
| const commandPanel = document.querySelector('.command-panel'); | |
| document.addEventListener('keydown', function(e) { | |
| if ((e.ctrlKey || e.metaKey) && e.key === 'k') { | |
| e.preventDefault(); | |
| commandPanel.classList.toggle('open'); | |
| } | |
| }); | |
| document.querySelector('.close-panel').addEventListener('click', function() { | |
| commandPanel.classList.remove('open'); | |
| }); | |
| // Floating action button | |
| document.querySelector('.fab').addEventListener('click', function() { | |
| commandPanel.classList.add('open'); | |
| }); | |
| // Cell selection functionality | |
| // Initialize cell click handlers | |
| const cells = document.querySelectorAll('.task-cell'); | |
| cells.forEach(cell => { | |
| cell.addEventListener('click', taskCellClickHandler); | |
| }); | |
| // Drag and drop functionality | |
| const taskItems = document.querySelectorAll('.task-item'); | |
| taskItems.forEach(item => { | |
| item.setAttribute('draggable', 'true'); | |
| item.addEventListener('dragstart', function(e) { | |
| e.dataTransfer.setData('text/plain', this.dataset.taskId || ''); | |
| this.classList.add('dragging'); | |
| }); | |
| item.addEventListener('dragend', function() { | |
| this.classList.remove('dragging'); | |
| }); | |
| }); | |
| cells.forEach(cell => { | |
| cell.addEventListener('dragover', function(e) { | |
| e.preventDefault(); | |
| if (!this.classList.contains('pto-cell')) { | |
| this.classList.add('drop-target'); | |
| } | |
| }); | |
| cell.addEventListener('dragleave', function() { | |
| this.classList.remove('drop-target'); | |
| }); | |
| cell.addEventListener('drop', function(e) { | |
| e.preventDefault(); | |
| this.classList.remove('drop-target'); | |
| // TODO: Handle the drop logic | |
| // const taskId = e.dataTransfer.getData('text/plain'); | |
| // Move task to this cell | |
| }); | |
| }); | |
| // Add Team Member functionality | |
| document.querySelector('.team-management .btn-primary').addEventListener('click', function() { | |
| const teamName = prompt('Enter team member name:'); | |
| if (teamName && teamName.trim()) { | |
| const initials = teamName.trim().split(' ').map(n => n[0]).join('').toUpperCase(); | |
| const calendarGrid = document.querySelector('.calendar-grid'); | |
| const dateCells = document.querySelectorAll('.date-column .date-cell'); | |
| // Create new team column | |
| const newColumn = document.createElement('div'); | |
| newColumn.className = 'team-column'; | |
| // Build member header | |
| const headerHTML = ` | |
| <div class="member-header"> | |
| <div class="member-avatar">${initials}</div> | |
| <div class="member-name">${teamName.toLowerCase()}</div> | |
| <button class="remove-col">×</button> | |
| </div> | |
| `; | |
| // Build task cells corresponding to each date cell | |
| let cellsHTML = ''; | |
| dateCells.forEach(() => { | |
| cellsHTML += '<div class="task-cell"></div>'; | |
| }); | |
| newColumn.innerHTML = headerHTML + cellsHTML; | |
| // Set up drag and drop for new cells | |
| newColumn.querySelectorAll('.task-cell').forEach(cell => { | |
| cell.addEventListener('dragover', function(e) { | |
| e.preventDefault(); | |
| if (!this.classList.contains('pto-cell')) { | |
| this.classList.add('drop-target'); | |
| } | |
| }); | |
| cell.addEventListener('dragleave', function() { | |
| this.classList.remove('drop-target'); | |
| }); | |
| cell.addEventListener('drop', function(e) { | |
| e.preventDefault(); | |
| this.classList.remove('drop-target'); | |
| }); | |
| }); | |
| // Insert before milestone column | |
| const milestoneColumn = document.querySelector('.milestone-column'); | |
| calendarGrid.insertBefore(newColumn, milestoneColumn); | |
| // Add remove functionality | |
| newColumn.querySelector('.remove-col').addEventListener('click', function(e) { | |
| e.stopPropagation(); | |
| if (confirm(`Remove ${teamName} from team?`)) { | |
| newColumn.remove(); | |
| } | |
| }); | |
| // Add cell click handlers to new cells | |
| newColumn.querySelectorAll('.task-cell').forEach(cell => { | |
| cell.addEventListener('click', taskCellClickHandler); | |
| // Make cells droppable for tasks | |
| cell.addEventListener('dragover', function(e) { | |
| e.preventDefault(); | |
| if (!this.classList.contains('pto-cell')) { | |
| this.classList.add('drop-target'); | |
| } | |
| }); | |
| cell.addEventListener('dragleave', function() { | |
| this.classList.remove('drop-target'); | |
| }); | |
| cell.addEventListener('drop', function(e) { | |
| e.preventDefault(); | |
| this.classList.remove('drop-target'); | |
| }); | |
| }); | |
| } | |
| }); | |
| function taskCellClickHandler(e) { | |
| // Don't select if clicking on a child element that has its own handler | |
| if (e.target !== this && e.target.closest('a')) return; | |
| // Toggle selection | |
| if (e.ctrlKey || e.metaKey) { | |
| // Multi-select | |
| this.classList.toggle('selected'); | |
| } else if (e.shiftKey) { | |
| // Range select | |
| // TODO: Implement range selection logic | |
| } else { | |
| // Single select | |
| document.querySelectorAll('.task-cell.selected').forEach(el => { | |
| el.classList.remove('selected'); | |
| }); | |
| this.classList.add('selected'); | |
| } | |
| // Focus on clicked cell for keyboard navigation | |
| this.focus(); | |
| } | |
| // Date range selector | |
| const rangeButtons = document.querySelectorAll('.range-btn'); | |
| rangeButtons.forEach(button => { | |
| button.addEventListener('click', function() { | |
| rangeButtons.forEach(btn => btn.classList.remove('active')); | |
| this.classList.add('active'); | |
| // TODO: Update calendar view based on selected range | |
| }); | |
| }); | |
| // Keyboard shortcuts | |
| document.addEventListener('keydown', function(e) { | |
| if (e.key === 'Escape') { | |
| // Clear selections | |
| document.querySelectorAll('.task-cell.selected').forEach(el => { | |
| el.classList.remove('selected'); | |
| }); | |
| } else if (e.key === 'Enter' && document.activeElement.classList.contains('task-cell')) { | |
| // Open task editor when pressing enter on a cell | |
| const selectedCell = document.activeElement; | |
| const taskTitle = prompt('Enter task title:'); | |
| if (taskTitle) { | |
| const hours = prompt('Estimated hours:'); | |
| const status = prompt('Status (complete/in-progress/blocked/not-started):'); | |
| selectedCell.innerHTML = ` | |
| <div class="task-item" data-status="${status || 'not-started'}"> | |
| <span class="status-indicator"></span> | |
| <span class="task-title">${taskTitle}</span> | |
| <span class="task-meta">${hours || '0'}h</span> | |
| </div> | |
| `; | |
| // Make the new task draggable | |
| selectedCell.querySelector('.task-item').setAttribute('draggable', 'true'); | |
| selectedCell.querySelector('.task-item').addEventListener('dragstart', function(e) { | |
| e.dataTransfer.setData('text/plain', this.dataset.taskId || ''); | |
| this.classList.add('dragging'); | |
| }); | |
| selectedCell.querySelector('.task-item').addEventListener('dragend', function() { | |
| this.classList.remove('dragging'); | |
| }); | |
| } | |
| } | |
| }); | |
| // Initialize with some default team members | |
| function initializeDefaultTeam() { | |
| const defaultMembers = ['Alice Smith', 'Bob Johnson', 'Charlie Brown']; | |
| defaultMembers.forEach(member => { | |
| const initials = member.split(' ').map(n => n[0]).join('').toUpperCase(); | |
| const calendarGrid = document.querySelector('.calendar-grid'); | |
| const newColumn = document.createElement('div'); | |
| newColumn.className = 'team-column'; | |
| newColumn.innerHTML = ` | |
| <div class="member-header"> | |
| <div class="member-avatar">${initials}</div> | |
| <div class="member-name">${member.toLowerCase().split(' ')[0]}</div> | |
| <button class="remove-col">×</button> | |
| </div> | |
| <div class="task-cell"></div> | |
| <div class="task-cell"></div> | |
| <div class="task-cell"></div> | |
| <div class="task-cell"></div> | |
| <div class="task-cell"></div> | |
| `; | |
| const milestoneColumn = document.querySelector('.milestone-column'); | |
| calendarGrid.insertBefore(newColumn, milestoneColumn); | |
| newColumn.querySelector('.remove-col').addEventListener('click', function(e) { | |
| e.stopPropagation(); | |
| if (confirm(`Remove ${member} from team?`)) { | |
| newColumn.remove(); | |
| } | |
| }); | |
| newColumn.querySelectorAll('.task-cell').forEach(cell => { | |
| cell.addEventListener('click', taskCellClickHandler); | |
| cell.tabIndex = 0; // Make cells focusable for keyboard navigation | |
| }); | |
| }); | |
| } | |
| // Call initialization | |
| initializeDefaultTeam(); | |
| }); | |
| // TODO: Add more advanced calendar functionality | |