Refactors calendar project structure and build configuration
Consolidates V2 codebase into main project directory Updates build script to support simplified entry points Removes redundant files and cleans up project organization Simplifies module imports and entry points for calendar application
This commit is contained in:
parent
9f360237cf
commit
863b433eba
200 changed files with 2331 additions and 16193 deletions
135
src/features/headerdrawer/HeaderDrawerLayoutEngine.ts
Normal file
135
src/features/headerdrawer/HeaderDrawerLayoutEngine.ts
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* HeaderDrawerLayoutEngine - Calculates row placement for header items
|
||||
*
|
||||
* Prevents visual overlap by assigning items to different rows when
|
||||
* they occupy the same columns. Uses a track-based algorithm similar
|
||||
* to V1's AllDayLayoutEngine.
|
||||
*
|
||||
* Each row can hold multiple items as long as they don't overlap in columns.
|
||||
* When an item spans columns that are already occupied, it's placed in the
|
||||
* next available row.
|
||||
*/
|
||||
|
||||
export interface IHeaderItemLayout {
|
||||
itemId: string;
|
||||
gridArea: string; // "row / col-start / row+1 / col-end"
|
||||
startColumn: number;
|
||||
endColumn: number;
|
||||
row: number;
|
||||
}
|
||||
|
||||
export interface IHeaderItemInput {
|
||||
id: string;
|
||||
columnStart: number; // 0-based column index
|
||||
columnEnd: number; // 0-based end column (inclusive)
|
||||
}
|
||||
|
||||
export class HeaderDrawerLayoutEngine {
|
||||
private tracks: boolean[][] = [];
|
||||
private columnCount: number;
|
||||
|
||||
constructor(columnCount: number) {
|
||||
this.columnCount = columnCount;
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset tracks for new layout calculation
|
||||
*/
|
||||
reset(): void {
|
||||
this.tracks = [new Array(this.columnCount).fill(false)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate layout for all items
|
||||
* Items should be sorted by start column for optimal packing
|
||||
*/
|
||||
calculateLayout(items: IHeaderItemInput[]): IHeaderItemLayout[] {
|
||||
this.reset();
|
||||
const layouts: IHeaderItemLayout[] = [];
|
||||
|
||||
for (const item of items) {
|
||||
const row = this.findAvailableRow(item.columnStart, item.columnEnd);
|
||||
|
||||
// Mark columns as occupied in this row
|
||||
for (let col = item.columnStart; col <= item.columnEnd; col++) {
|
||||
this.tracks[row][col] = true;
|
||||
}
|
||||
|
||||
// gridArea format: "row / col-start / row+1 / col-end"
|
||||
// CSS grid uses 1-based indices
|
||||
layouts.push({
|
||||
itemId: item.id,
|
||||
gridArea: `${row + 1} / ${item.columnStart + 1} / ${row + 2} / ${item.columnEnd + 2}`,
|
||||
startColumn: item.columnStart,
|
||||
endColumn: item.columnEnd,
|
||||
row: row + 1 // 1-based for CSS
|
||||
});
|
||||
}
|
||||
|
||||
return layouts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate layout for a single new item
|
||||
* Useful for real-time drag operations
|
||||
*/
|
||||
calculateSingleLayout(item: IHeaderItemInput): IHeaderItemLayout {
|
||||
const row = this.findAvailableRow(item.columnStart, item.columnEnd);
|
||||
|
||||
// Mark columns as occupied
|
||||
for (let col = item.columnStart; col <= item.columnEnd; col++) {
|
||||
this.tracks[row][col] = true;
|
||||
}
|
||||
|
||||
return {
|
||||
itemId: item.id,
|
||||
gridArea: `${row + 1} / ${item.columnStart + 1} / ${row + 2} / ${item.columnEnd + 2}`,
|
||||
startColumn: item.columnStart,
|
||||
endColumn: item.columnEnd,
|
||||
row: row + 1
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first row where all columns in range are available
|
||||
*/
|
||||
private findAvailableRow(startCol: number, endCol: number): number {
|
||||
for (let row = 0; row < this.tracks.length; row++) {
|
||||
if (this.isRowAvailable(row, startCol, endCol)) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
|
||||
// Add new row if all existing rows are occupied
|
||||
this.tracks.push(new Array(this.columnCount).fill(false));
|
||||
return this.tracks.length - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if columns in range are all available in given row
|
||||
*/
|
||||
private isRowAvailable(row: number, startCol: number, endCol: number): boolean {
|
||||
for (let col = startCol; col <= endCol; col++) {
|
||||
if (this.tracks[row][col]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of rows currently in use
|
||||
*/
|
||||
getRowCount(): number {
|
||||
return this.tracks.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update column count (e.g., when view changes)
|
||||
*/
|
||||
setColumnCount(count: number): void {
|
||||
this.columnCount = count;
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue