taskforge-pro / components /timeline-sidebar.js
Fadikkop's picture
Promote version 4549c0d to main
a12aab2 verified
class TimelineSidebar extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.render();
this.setupEventListeners();
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
position: fixed;
right: 0;
top: 0;
height: 100vh;
width: 300px;
background: #1f2937;
border-left: 1px solid #374151;
z-index: 30;
transform: translateX(100%);
transition: transform 0.3s ease;
overflow-y: auto;
}
:host(.open) {
transform: translateX(0);
}
.header {
padding: 1rem;
border-bottom: 1px solid #374151;
display: flex;
justify-content: space-between;
align-items: center;
}
.timeline-container {
padding: 1rem;
}
.timeline-hour {
position: relative;
min-height: 60px;
border-bottom: 1px solid #374151;
padding-left: 50px;
}
.hour-label {
position: absolute;
left: 10px;
top: 5px;
font-size: 12px;
color: #9ca3af;
}
.task-drop-area {
height: 100%;
min-height: 60px;
}
.toggle-btn {
position: fixed;
right: 300px;
top: 50%;
transform: translateY(-50%);
background: #1f2937;
border: 1px solid #374151;
border-right: none;
padding: 1rem 0.5rem;
border-radius: 5px 0 0 5px;
cursor: pointer;
z-index: 30;
}
.task-block {
background: #374151;
border-left: 3px solid #f97316;
padding: 0.5rem;
margin: 0.5rem 0;
border-radius: 4px;
}
</style>
<button class="toggle-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="15 18 9 12 15 6"></polyline>
</svg>
</button>
<div class="header">
<h3>Timeline</h3>
<button id="close-timeline">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="timeline-container" id="timeline-hours">
${Array.from({ length: 24 }, (_, i) => `
<div class="timeline-hour" data-hour="${i}">
<span class="hour-label">${i.toString().padStart(2, '0')}:00</span>
<div class="task-drop-area" data-hour="${i}"></div>
</div>
`).join('')}
</div>
`;
}
setupEventListeners() {
const toggleBtn = this.shadowRoot.querySelector('.toggle-btn');
toggleBtn.addEventListener('click', () => {
this.classList.toggle('open');
const icon = toggleBtn.querySelector('svg');
if (this.classList.contains('open')) {
icon.innerHTML = '<polyline points="15 18 9 12 15 6"></polyline>';
} else {
icon.innerHTML = '<polyline points="9 18 15 12 9 6"></polyline>';
}
});
// Setup drag and drop
this.shadowRoot.addEventListener('dragover', (e) => {
if (e.target.classList.contains('task-drop-area')) {
e.preventDefault();
e.target.style.backgroundColor = '#37415170';
}
});
this.shadowRoot.addEventListener('dragleave', (e) => {
if (e.target.classList.contains('task-drop-area')) {
e.target.style.backgroundColor = '';
}
});
this.shadowRoot.addEventListener('drop', (e) => {
if (e.target.classList.contains('task-drop-area')) {
e.preventDefault();
e.target.style.backgroundColor = '';
const taskId = e.dataTransfer.getData('text/plain');
const hour = parseInt(e.target.dataset.hour);
this.dispatchEvent(new CustomEvent('task-dropped', {
detail: { taskId, hour }
}));
}
});
}
}
customElements.define('timeline-sidebar', TimelineSidebar);