Adds core calendar package components including: - Base services for events, resources, and settings - Calendar app and orchestrator - Build and bundling configuration - IndexedDB storage setup Prepares foundational architecture for calendar functionality
91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
import { IRenderer, IRenderContext } from './IGroupingRenderer';
|
|
|
|
/**
|
|
* Entity must have id
|
|
*/
|
|
export interface IGroupingEntity {
|
|
id: string;
|
|
}
|
|
|
|
/**
|
|
* Configuration for a grouping renderer
|
|
*/
|
|
export interface IGroupingRendererConfig {
|
|
elementTag: string; // e.g., 'swp-team-header'
|
|
idAttribute: string; // e.g., 'teamId' -> data-team-id
|
|
colspanVar: string; // e.g., '--team-cols'
|
|
}
|
|
|
|
/**
|
|
* Abstract base class for grouping renderers
|
|
*
|
|
* Handles:
|
|
* - Fetching entities by IDs
|
|
* - Calculating colspan from parentChildMap
|
|
* - Creating header elements
|
|
* - Appending to container
|
|
*
|
|
* Subclasses override:
|
|
* - renderHeader() for custom content
|
|
* - getDisplayName() for entity display text
|
|
*/
|
|
export abstract class BaseGroupingRenderer<T extends IGroupingEntity> implements IRenderer {
|
|
abstract readonly type: string;
|
|
protected abstract readonly config: IGroupingRendererConfig;
|
|
|
|
/**
|
|
* Fetch entities from service
|
|
*/
|
|
protected abstract getEntities(ids: string[]): Promise<T[]>;
|
|
|
|
/**
|
|
* Get display name for entity
|
|
*/
|
|
protected abstract getDisplayName(entity: T): string;
|
|
|
|
/**
|
|
* Main render method - handles common logic
|
|
*/
|
|
async render(context: IRenderContext): Promise<void> {
|
|
const allowedIds = context.filter[this.type] || [];
|
|
if (allowedIds.length === 0) return;
|
|
|
|
const entities = await this.getEntities(allowedIds);
|
|
const dateCount = context.filter['date']?.length || 1;
|
|
const childIds = context.childType ? context.filter[context.childType] || [] : [];
|
|
|
|
for (const entity of entities) {
|
|
const entityChildIds = context.parentChildMap?.[entity.id] || [];
|
|
const childCount = entityChildIds.filter(id => childIds.includes(id)).length;
|
|
const colspan = childCount * dateCount;
|
|
|
|
const header = document.createElement(this.config.elementTag);
|
|
header.dataset[this.config.idAttribute] = entity.id;
|
|
header.style.setProperty(this.config.colspanVar, String(colspan));
|
|
|
|
// Allow subclass to customize header content
|
|
this.renderHeader(entity, header, context);
|
|
|
|
context.headerContainer.appendChild(header);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Override this method for custom header rendering
|
|
* Default: just sets textContent to display name
|
|
*/
|
|
protected renderHeader(entity: T, header: HTMLElement, _context: IRenderContext): void {
|
|
header.textContent = this.getDisplayName(entity);
|
|
}
|
|
|
|
/**
|
|
* Helper to render a single entity header.
|
|
* Can be used by subclasses that override render() but want consistent header creation.
|
|
*/
|
|
protected createHeader(entity: T, context: IRenderContext): HTMLElement {
|
|
const header = document.createElement(this.config.elementTag);
|
|
header.dataset[this.config.idAttribute] = entity.id;
|
|
this.renderHeader(entity, header, context);
|
|
return header;
|
|
}
|
|
}
|