refactor: use abstract ITEM placeholders with dynamic property mapping

Changed from fixed TASK placeholders to flexible ITEM placeholders that
automatically map all CSV fields to template placeholders.

Key changes:
- Renamed task-template → item-template in all templates
- Changed TASK_* → ITEM_* placeholder naming
- Implemented dynamic placeholder generation from item properties
- Any field in fieldMapping now creates ITEM_{FIELD} placeholder
- Updated all tests and documentation

Naming convention: CSV field → item.property → ITEM_PROPERTY
Example: "assignee" → item.assignee → {{ITEM_ASSIGNEE}}

This enables users to add custom fields without modifying generator code:
- Add "assignee": "Assignee" to fieldMapping
- Use {{ITEM_ASSIGNEE}} in template
- No code changes required

Benefits:
- More flexible and extensible
- Clearer abstraction (items vs tasks)
- Consistent naming convention
- Better documented

All 56 tests passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-27 23:17:34 +01:00
parent dd3ba4df58
commit 2bab447fa8
7 changed files with 86 additions and 57 deletions

View File

@@ -12,7 +12,7 @@ A valid template-v2.svg file must contain:
2. **`<defs>` section** containing three required template elements:
- `<g id="month-template">` - Defines how each month column is rendered
- `<g id="lane-template">` - Defines how each lane (epic/swimlane) is rendered
- `<g id="task-template">` - Defines how each task item is rendered
- `<g id="item-template">` - Defines how each task item is rendered
3. **Main content area** with `{{MONTHS}}` and `{{LANES}}` placeholders
4. **Optional styling** (gradients, filters, patterns, etc.)
@@ -37,11 +37,11 @@ A valid template-v2.svg file must contain:
font-family="Arial" font-size="14" font-weight="bold" fill="#212121">{{LANE_NAME}}</text>
</g>
<!-- Task template -->
<g id="task-template" style="display:none">
<circle cx="{{TASK_X}}" cy="{{TASK_Y}}" r="6" fill="#1976D2"/>
<!-- Item template -->
<g id="item-template" style="display:none">
<circle cx="{{ITEM_X}}" cy="{{ITEM_Y}}" r="6" fill="#1976D2"/>
<text x="{{TEXT_X}}" y="{{TEXT_Y}}"
font-family="Arial" font-size="11" fill="#424242">{{TASK_ID}} {{TASK_TITLE}}</text>
font-family="Arial" font-size="11" fill="#424242">{{ITEM_ID}} {{ITEM_TITLE}}</text>
</g>
</defs>
@@ -80,16 +80,38 @@ A valid template-v2.svg file must contain:
| `{{LABEL_Y}}` | Y position for lane label | 140 |
| `{{LANE_NAME}}` | Lane name text (XML-escaped) | "Development" |
### Task Template Placeholders
### Item Template Placeholders
| Placeholder | Description | Example Value |
|------------|-------------|---------------|
| `{{TASK_X}}` | X position of task marker | 400 |
| `{{TASK_Y}}` | Y position of task marker | 150 |
| `{{TEXT_X}}` | X position for task text | 412 |
| `{{TEXT_Y}}` | Y position for task text | 154 |
| `{{TASK_ID}}` | Task ID (XML-escaped) | "T-123" |
| `{{TASK_TITLE}}` | Task title (XML-escaped) | "Implement feature" |
| `{{ITEM_X}}` | X position of item marker | 400 |
| `{{ITEM_Y}}` | Y position of item marker | 150 |
| `{{TEXT_X}}` | X position for item text | 412 |
| `{{TEXT_Y}}` | Y position for item text | 154 |
| `{{ITEM_ID}}` | Item ID (XML-escaped) | "T-123" |
| `{{ITEM_TITLE}}` | Item title (XML-escaped) | "Implement feature" |
**Dynamic Data Placeholders:**
The generator automatically creates placeholders for **all properties** in your CSV data using the naming convention: `ITEM_{PROPERTY_UPPERCASE}`.
For example, if your `fieldMapping` includes:
```json
{
"id": "ID",
"title": "Title",
"assignee": "Assignee",
"priority": "Priority"
}
```
The following placeholders become available:
- `{{ITEM_ID}}` - from the `id` field
- `{{ITEM_TITLE}}` - from the `title` field
- `{{ITEM_ASSIGNEE}}` - from the `assignee` field
- `{{ITEM_PRIORITY}}` - from the `priority` field
**Note:** The `due` field is used for positioning and is not available as a placeholder (use `{{MONTH_LABEL}}` for date display).
### Global Placeholders
@@ -107,7 +129,7 @@ These appear in the main template body (not in template elements):
1. Open template-v2.svg in Inkscape
2. Locate template elements in the Layers panel (inside `<defs>`)
3. Edit shapes, colors, fonts, etc. as needed
4. **Important**: Keep `id="month-template"`, `id="lane-template"`, `id="task-template"` unchanged
4. **Important**: Keep `id="month-template"`, `id="lane-template"`, `id="item-template"` unchanged
5. **Important**: Keep `{{PLACEHOLDER}}` text exactly as is - these are replaced at runtime
6. Save file (keep SVG format, avoid Inkscape-specific extensions)
@@ -190,8 +212,8 @@ Use SVG filters:
</feMerge>
</filter>
<g id="task-template" style="display:none">
<circle cx="{{TASK_X}}" cy="{{TASK_Y}}" r="6" fill="#1976D2" filter="url(#dropShadow)"/>
<g id="item-template" style="display:none">
<circle cx="{{ITEM_X}}" cy="{{ITEM_Y}}" r="6" fill="#1976D2" filter="url(#dropShadow)"/>
...
</g>
</defs>
@@ -229,7 +251,7 @@ To change the overall layout, you would need to modify generator.js. Templates c
- Ensure template has all three required elements in `<defs>`:
- `<g id="month-template">`
- `<g id="lane-template">`
- `<g id="task-template">`
- `<g id="item-template">`
- Check that IDs are exactly as shown (case-sensitive)
- Verify elements are inside `<defs>` section