diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 6916dda..b2dc50e 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -13,7 +13,10 @@ "WebFetch(domain:raw.githubusercontent.com)", "Bash(npm run css:analyze:*)", "Bash(npm run test:run:*)", - "Bash(cd:*)" + "Bash(cd:*)", + "Bash(powershell -Command \"Get-ChildItem -Path src -Directory | Select-Object -ExpandProperty Name\")", + "Bash(powershell -Command \"Get-ChildItem -Path src -Filter ''index.ts'' -Recurse | Select-Object -ExpandProperty FullName\")", + "Bash(powershell -Command:*)" ], "deny": [], "ask": [] diff --git a/.workbench/inspiration.md b/.workbench/inspiration.md deleted file mode 100644 index ffcae70..0000000 --- a/.workbench/inspiration.md +++ /dev/null @@ -1,266 +0,0 @@ -Selvfølgelig—her er en **opdateret, selvstændig `.md`-spec**, som **understøtter variable antal resources per team**, dynamisk kolonnebredde, ingen inline layout-styles, pipeline‐rendering 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. - -``` - ---- - -``` diff --git a/build.js b/build.js index 296a1ca..df1d600 100644 --- a/build.js +++ b/build.js @@ -32,9 +32,9 @@ async function renameFiles(dir) { // Build with esbuild async function build() { try { - // Main calendar bundle (with DI) + // Calendar standalone bundle (no DI) await esbuild.build({ - entryPoints: ['src/index.ts'], + entryPoints: ['src/entry.ts'], bundle: true, outfile: 'wwwroot/js/calendar.js', format: 'esm', @@ -42,40 +42,26 @@ async function build() { target: 'es2020', minify: false, keepNames: true, + platform: 'browser' + }); + + console.log('Calendar bundle created: wwwroot/js/calendar.js'); + + // Demo bundle (with DI transformer for autowiring) + await esbuild.build({ + entryPoints: ['src/demo/index.ts'], + bundle: true, + outfile: 'wwwroot/js/demo.js', + format: 'esm', + sourcemap: 'inline', + target: 'es2020', + minify: false, + keepNames: true, platform: 'browser', plugins: [NovadiUnplugin.esbuild({ debug: false, enableAutowiring: true, performanceLogging: true })] }); - // V2 standalone bundle (no DI, no dependencies on main calendar) - await esbuild.build({ - entryPoints: ['src/v2/entry.ts'], - bundle: true, - outfile: 'wwwroot/js/calendar-v2.js', - format: 'esm', - sourcemap: 'inline', - target: 'es2020', - minify: false, - keepNames: true, - platform: 'browser' - }); - - console.log('V2 bundle created: wwwroot/js/calendar-v2.js'); - - // V2 demo bundle (with DI transformer for autowiring) - await esbuild.build({ - entryPoints: ['src/v2/demo/index.ts'], - bundle: true, - outfile: 'wwwroot/js/v2-demo.js', - format: 'esm', - sourcemap: 'inline', - target: 'es2020', - minify: false, - keepNames: true, - platform: 'browser', - plugins: [NovadiUnplugin.esbuild({ debug: false, enableAutowiring: true })] - }); - - console.log('V2 demo bundle created: wwwroot/js/v2-demo.js'); + console.log('Demo bundle created: wwwroot/js/demo.js'); } catch (error) { console.error('Build failed:', error); diff --git a/reports/css-analysis-report.html b/reports/css-analysis-report.html index 586ad68..156c1df 100644 --- a/reports/css-analysis-report.html +++ b/reports/css-analysis-report.html @@ -141,7 +141,7 @@
- 3 unused rules + 16 unused rules - Original: 6275 | After purge: 6203 + Original: 7087 | After purge: 6800
- - 20 unused rules + + 26 unused rules - Original: 7298 | After purge: 6810 + Original: 7047 | After purge: 6504
- 0 unused rules + 1 unused rules - Original: 1701 | After purge: 1701 + Original: 1574 | After purge: 1570
-✅ No unused CSS found!
+ +