Improves header drawer layout and drag behavior
Implements dynamic item positioning and layout recalculation for header drawer - Adds ISO date tracking for header items - Introduces dynamic row allocation algorithm - Updates drawer expansion logic during drag operations - Calculates and adjusts drawer height based on item tracks
This commit is contained in:
parent
7cb89e2ec5
commit
f7f1f8afe0
2 changed files with 81 additions and 9 deletions
|
|
@ -218,8 +218,10 @@ export class HeaderDrawerRenderer {
|
||||||
// Remember if drawer was already expanded
|
// Remember if drawer was already expanded
|
||||||
this.wasExpandedBeforeDrag = this.headerDrawerManager.isExpanded();
|
this.wasExpandedBeforeDrag = this.headerDrawerManager.isExpanded();
|
||||||
|
|
||||||
// Expand drawer with animation
|
// Expand to at least 1 row if collapsed, otherwise keep current height
|
||||||
this.headerDrawerManager.expand();
|
if (!this.wasExpandedBeforeDrag) {
|
||||||
|
this.headerDrawerManager.expandToRows(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Store reference to source element
|
// Store reference to source element
|
||||||
this.sourceElement = payload.element;
|
this.sourceElement = payload.element;
|
||||||
|
|
@ -228,10 +230,16 @@ export class HeaderDrawerRenderer {
|
||||||
const item = document.createElement('swp-header-item');
|
const item = document.createElement('swp-header-item');
|
||||||
item.dataset.eventId = payload.eventId;
|
item.dataset.eventId = payload.eventId;
|
||||||
item.dataset.itemType = payload.itemType;
|
item.dataset.itemType = payload.itemType;
|
||||||
item.dataset.date = payload.sourceDate;
|
|
||||||
item.dataset.duration = String(payload.duration);
|
item.dataset.duration = String(payload.duration);
|
||||||
item.textContent = payload.title;
|
item.textContent = payload.title;
|
||||||
|
|
||||||
|
// Set start/end as ISO dates (for recalculateDrawerLayout)
|
||||||
|
const startDate = new Date(payload.sourceDate);
|
||||||
|
const endDate = new Date(payload.sourceDate);
|
||||||
|
endDate.setDate(endDate.getDate() + payload.duration - 1);
|
||||||
|
item.dataset.start = startDate.toISOString();
|
||||||
|
item.dataset.end = endDate.toISOString();
|
||||||
|
|
||||||
// Apply color class if present
|
// Apply color class if present
|
||||||
if (payload.colorClass) {
|
if (payload.colorClass) {
|
||||||
item.classList.add(payload.colorClass);
|
item.classList.add(payload.colorClass);
|
||||||
|
|
@ -259,13 +267,19 @@ export class HeaderDrawerRenderer {
|
||||||
private handleDragMove(payload: IDragMoveHeaderPayload): void {
|
private handleDragMove(payload: IDragMoveHeaderPayload): void {
|
||||||
if (!this.currentItem) return;
|
if (!this.currentItem) return;
|
||||||
|
|
||||||
// Update column position (duration=1 for now)
|
// Update column position
|
||||||
const col = payload.columnIndex + 1;
|
const col = payload.columnIndex + 1;
|
||||||
const duration = parseInt(this.currentItem.dataset.duration || '1', 10);
|
const duration = parseInt(this.currentItem.dataset.duration || '1', 10);
|
||||||
const endCol = col + duration;
|
const endCol = col + duration;
|
||||||
|
|
||||||
this.currentItem.style.gridArea = `1 / ${col} / 2 / ${endCol}`;
|
this.currentItem.style.gridArea = `1 / ${col} / 2 / ${endCol}`;
|
||||||
this.currentItem.dataset.date = payload.dateKey;
|
|
||||||
|
// Update start/end dates based on new position
|
||||||
|
const startDate = new Date(payload.dateKey);
|
||||||
|
const endDate = new Date(payload.dateKey);
|
||||||
|
endDate.setDate(endDate.getDate() + duration - 1);
|
||||||
|
this.currentItem.dataset.start = startDate.toISOString();
|
||||||
|
this.currentItem.dataset.end = endDate.toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -286,13 +300,74 @@ export class HeaderDrawerRenderer {
|
||||||
// Remove dragging state
|
// Remove dragging state
|
||||||
this.currentItem.classList.remove('dragging');
|
this.currentItem.classList.remove('dragging');
|
||||||
|
|
||||||
// TODO: Emit event to persist allDay=true change
|
// Recalculate layout for all items in drawer
|
||||||
|
this.recalculateDrawerLayout();
|
||||||
|
|
||||||
// Clear references
|
// Clear references
|
||||||
this.currentItem = null;
|
this.currentItem = null;
|
||||||
this.sourceElement = null;
|
this.sourceElement = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculate layout for all items currently in the drawer
|
||||||
|
* Called after drop to reposition items and adjust height
|
||||||
|
*/
|
||||||
|
private recalculateDrawerLayout(): void {
|
||||||
|
const drawer = document.querySelector('swp-header-drawer');
|
||||||
|
if (!drawer) return;
|
||||||
|
|
||||||
|
const items = Array.from(drawer.querySelectorAll('swp-header-item')) as HTMLElement[];
|
||||||
|
if (items.length === 0) return;
|
||||||
|
|
||||||
|
// Get visible dates from existing items
|
||||||
|
const visibleDates = this.getVisibleDatesFromDOM();
|
||||||
|
if (visibleDates.length === 0) return;
|
||||||
|
|
||||||
|
// Build layout data from DOM items
|
||||||
|
const itemData = items.map(item => ({
|
||||||
|
element: item,
|
||||||
|
start: new Date(item.dataset.start || ''),
|
||||||
|
end: new Date(item.dataset.end || '')
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Calculate new layout using track algorithm
|
||||||
|
const tracks: boolean[][] = [new Array(visibleDates.length).fill(false)];
|
||||||
|
|
||||||
|
for (const item of itemData) {
|
||||||
|
const startCol = this.getColIndex(item.start, visibleDates);
|
||||||
|
const endCol = this.getColIndex(item.end, visibleDates);
|
||||||
|
|
||||||
|
const colStart = Math.max(0, startCol);
|
||||||
|
const colEnd = (endCol !== -1 ? endCol : visibleDates.length - 1) + 1;
|
||||||
|
|
||||||
|
const row = this.findAvailableRow(tracks, colStart, colEnd);
|
||||||
|
|
||||||
|
for (let c = colStart; c < colEnd; c++) {
|
||||||
|
tracks[row][c] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update element position
|
||||||
|
item.element.style.gridArea = `${row + 1} / ${colStart + 1} / ${row + 2} / ${colEnd + 1}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update drawer height
|
||||||
|
const rowCount = tracks.length;
|
||||||
|
this.headerDrawerManager.expandToRows(rowCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get visible dates from header columns in DOM
|
||||||
|
*/
|
||||||
|
private getVisibleDatesFromDOM(): string[] {
|
||||||
|
const columns = document.querySelectorAll('swp-day-column');
|
||||||
|
const dates: string[] = [];
|
||||||
|
columns.forEach(col => {
|
||||||
|
const date = (col as HTMLElement).dataset.date;
|
||||||
|
if (date && !dates.includes(date)) dates.push(date);
|
||||||
|
});
|
||||||
|
return dates;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup preview item and restore source visibility
|
* Cleanup preview item and restore source visibility
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,6 @@ swp-header-drawer {
|
||||||
grid-template-columns: subgrid;
|
grid-template-columns: subgrid;
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
grid-row: 2;
|
grid-row: 2;
|
||||||
grid-auto-rows: 28px;
|
|
||||||
gap: 2px 0;
|
|
||||||
height: 0;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: var(--color-background-alt);
|
background: var(--color-background-alt);
|
||||||
border-bottom: 1px solid var(--color-border);
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue