Calendar/.workbench/inspiration.md
Janus C. H. Knudsen c16e432b29 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
2025-12-09 15:24:19 +01:00

266 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.
```
---
```