Refactors rendering pipeline with flexible data handling

Removes hardcoded data from render context, allowing more dynamic renderer implementation

Changes include:
- Decoupling data retrieval from render context
- Simplifying renderer interface
- Supporting more flexible data traversal strategies

Prepares for more modular and adaptable rendering approach
This commit is contained in:
Janus C. H. Knudsen 2025-12-09 15:24:19 +01:00
parent a3a1b9a421
commit c16e432b29
5 changed files with 517 additions and 22 deletions

266
.workbench/inspiration.md Normal file
View file

@ -0,0 +1,266 @@
Selvfølgelig—her er en **opdateret, selvstændig `.md`-spec**, som **understøtter variable antal resources per team**, dynamisk kolonnebredde, ingen inline layout-styles, pipelinerendering i grupper, og CSS-controlling via custom properties.
Kopier → gem som fx:
`grid-render-pipeline-dynamic-columns.md`
---
````md
# Grid Render Pipeline — Dynamic Columns Spec
Denne specifikation beskriver en generisk render-pipeline til at bygge et
dynamisk CSS Grid layout, hvor hver "gruppe" (teams, resources, dates) har sin
egen renderer og pipeline-styring. Layoutet understøtter **variable antal
resources pr. team** og beregner automatisk antal kolonner. Ingen inline-styles
til positionering anvendes.
---
## ✨ Formål
- Ét globalt CSS Grid.
- Variabelt antal resources pr. team → dynamisk antal kolonner.
- CSS-grid auto-placerer rækker.
- Ingen inline styling af layout (ingen `element.style.gridRow = ...`).
- CSS custom properties bruges til at definere dynamiske spænder.
- Renderere har ens interface og bindes i pipeline.
- `pipeline.run(ctx)` executer alle renderers i rækkefølge.
- Hver renderer kan hente sin egen data (API, async osv.).
---
## 🧩 Data Model
```ts
type DateString = string;
interface Resource {
id: string;
name: string;
dates: DateString[];
}
interface Team {
id: string;
name: string;
resources: Resource[];
}
````
---
## 🧠 Context
```ts
interface RenderContext {
grid: HTMLElement; // root grid container
teams: Team[]; // data
}
```
`grid` er HTML-elementet med `display:grid`, og `teams` er data.
---
## 🎨 CSS Layout
Grid kolonner bestemmes dynamisk via CSS variablen `--total-cols`.
```css
.grid {
display: grid;
grid-template-columns: repeat(var(--total-cols), minmax(0, 1fr));
gap: 6px 10px;
}
.cell {
font-size: 0.9rem;
}
```
### Teams (øverste række)
Hver team-header spænder **antal resources for team'et**:
```css
.team-header {
grid-column: span var(--team-cols, 1);
font-weight: 700;
border-bottom: 1px solid #ccc;
padding: 4px 2px;
}
```
### Resources (2. række)
```css
.resource-cell {
padding: 4px 2px;
background: #f5f5f5;
border-radius: 4px;
text-align: center;
font-weight: 600;
}
```
### Dates (3. række)
```css
.dates-cell { padding: 2px 0; }
.dates-list {
display: flex;
flex-wrap: wrap;
gap: 4px;
justify-content: center;
}
.date-pill {
padding: 3px 6px;
background: #e3e3e3;
border-radius: 4px;
font-size: 0.8rem;
}
```
---
## 🔧 Beregning af kolonner
**Total cols = sum(resources.length for all teams)**
```ts
const totalCols = ctx.teams.reduce((sum, t) => sum + t.resources.length, 0);
ctx.grid.style.setProperty('--total-cols', totalCols.toString());
```
For hvert team defineres hvor mange kolonner det spænder:
```ts
cell.style.setProperty('--team-cols', team.resources.length.toString());
```
> Bemærk: vi bruger **kun CSS vars** til layoutparametre ikke inline
> grid-row/grid-column.
---
## ⚙ Renderer Interface
```ts
interface Renderer {
id: string;
next: Renderer | null;
render(ctx: RenderContext): void;
}
```
### Factory
```ts
function createRenderer(id: string, fn: (ctx: RenderContext) => void): Renderer {
return {
id,
next: null,
render(ctx) {
fn(ctx);
if (this.next) this.next.render(ctx);
}
};
}
```
---
## 🧱 De tre render-lag (grupper)
### Teams
* Appender én `.team-header` per team.
* Sætter `--team-cols`.
### Resources
* Appender én `.resource-cell` per resource.
* Foregår i teams-orden → CSS auto-row sørger for næste række.
### Dates
* Appender én `.dates-cell` per resource.
* Hver celle indeholder flere `.date-pill`.
Append-rækkefølge giver 3 rækker automatisk:
1. teams, 2) resources, 3) dates.
---
## 🔗 Pipeline
```ts
function buildPipeline(renderers: Renderer[]) {
for (let i = 0; i < renderers.length - 1; i++) {
renderers[i].next = renderers[i + 1];
}
const first = renderers[0] ?? null;
return {
run(ctx: RenderContext) {
if (first) first.render(ctx);
}
};
}
```
### Brug
```ts
const pipeline = buildPipeline([
teamsRenderer,
resourcesRenderer,
datesRenderer
]);
pipeline.run(ctx);
```
---
## 🚀 Kørsel
```ts
// 1) beregn total kolonner
const totalCols = ctx.teams.reduce((sum, t) => sum + t.resources.length, 0);
ctx.grid.style.setProperty('--total-cols', totalCols);
// 2) pipeline
pipeline.run(ctx);
```
CSS klarer resten.
---
## 🧽 Principper
* **Ingen inline style-positionering**.
* **CSS Grid** owner layout.
* **JS** owner data & rækkefølge.
* **Renderers** er udskiftelige og genbrugelige.
* **Append i grupper** = rækker automatisk.
* **CSS vars** styrer spans dynamisk.
---
## ✔ TL;DR
* Grid-cols bestemmes ud fra data.
* Team-header `span = resources.length`.
* Append rækkefølge = rækker.
* Renderere i pipeline.
* Ingen koordinater, ingen inline layout-styles.
```
---
```