feat: add DOM-based prototype template system for full Inkscape editability

Implements a new templating approach that allows complete visual control
in Inkscape while maintaining 100% valid SVG.

New Features:
- DOM-based generator using DOMParser and cloneNode()
- Prototype elements (month-proto, lane-proto, item-proto) instead of string templates
- Full WYSIWYG editing in Inkscape - see exactly how timeline will look
- Auto-detection of template type (prototype vs template-v2)
- Text element mapping via IDs (e.g., id="item-title")
- SVG transforms for positioning instead of placeholder replacement

Implementation:
- generator-dom.js: New DOM-based generator with cloning logic
- engine.js: Auto-detect template type and use appropriate generator
- example-proto/: Complete working example with prototype template
- PROTOTYPE_TEMPLATES.md: Comprehensive guide for creating prototype templates

Benefits:
- No string placeholders ({{PLACEHOLDER}}) needed
- Native SVG editing workflow
- Better performance (DOM manipulation vs regex)
- Easier maintenance and styling
- Backward compatible (old template-v2 still works)

Template Structure:
- Prototypes with specific IDs visible in SVG (hidden after cloning)
- Container groups for generated content
- CSS classes for styling
- Text elements with IDs matching field names

All 56 tests still passing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-23 23:50:37 +01:00
parent a5811040e7
commit 5bec61740b
10 changed files with 837 additions and 6 deletions

339
PROTOTYPE_TEMPLATES.md Normal file
View File

@@ -0,0 +1,339 @@
# Prototype-Based Templates Guide
## Overview
The timeline generator now supports **prototype-based templates** using DOM cloning. This is the recommended approach for creating custom timeline designs because:
-**100% Valid SVG** - Edit directly in Inkscape with full visual control
-**WYSIWYG** - See exactly how your timeline will look
-**No String Placeholders** - No need for `{{PLACEHOLDER}}` syntax
-**Better Performance** - Uses native DOM manipulation
-**Easier Maintenance** - Visual editing instead of code
## How It Works
1. **Create Prototypes in Inkscape**
- Design visual elements (month headers, lanes, items) with specific IDs
- Style them exactly as you want them to appear
- The generator will clone these elements for each data item
2. **Generator Clones Prototypes**
- Each prototype is deep-cloned using DOM
- Positioned using SVG transforms
- Text content updated from your data
- Appended to target containers
3. **Prototypes Hidden**
- Original prototypes are hidden (`display:none`) after cloning
- Only the cloned, data-filled elements remain visible
## Template Structure
### Required Prototype Elements
Your SVG must contain these three prototype groups:
```xml
<g id="month-proto">
<!-- Month header design -->
<line x1="0" y1="120" x2="0" y2="600" class="month-grid" />
<text x="4" y="90" class="month-label">Jan 25</text>
</g>
<g id="lane-proto">
<!-- Lane/swimlane design -->
<rect x="40" y="-24" width="1000" height="80" class="lane-bg" />
<text x="56" y="-4" class="lane-label">Lane Name</text>
</g>
<g id="item-proto">
<!-- Task/item marker design -->
<circle cx="0" cy="0" r="5" class="item-marker" />
<text x="12" y="4" class="item-title">Task Title</text>
<text x="12" y="-8" class="item-id">T-123</text>
</g>
```
### Required Container Elements
The generator will place clones in these containers (created automatically if missing):
```xml
<g id="months-container"></g>
<g id="lanes-container"></g>
<g id="items-container"></g>
```
### Text Element Mapping
Text elements in the item prototype are matched to your data fields:
- Elements with `id="item-{fieldname}"` (e.g., `id="item-title"`, `id="item-id"`)
- Or elements with IDs containing the field name
- Or the first `<text>` element if no specific match found
Example:
```xml
<g id="item-proto">
<text id="item-title">Placeholder Title</text>
<text id="item-id">T-000</text>
<text id="item-status">TODO</text>
</g>
```
Will map to CSV columns based on your `fieldMapping` in project.json:
```json
{
"fieldMapping": {
"title": "Title",
"id": "ID",
"status": "Status"
}
}
```
## Creating a Prototype Template in Inkscape
### Step 1: Start with a Base SVG
1. Open Inkscape
2. Create new document (File → New)
3. Set document size (recommended: 1200x800px)
### Step 2: Design Your Month Prototype
1. Create a group (Ctrl+G) and name it `month-proto` in the Object Properties panel
2. Add elements:
- Vertical line for grid separator
- Text label for month name
3. Style using Inkscape's fill, stroke, font tools
4. Position at x=220 (will be translated for each month)
### Step 3: Design Your Lane Prototype
1. Create group named `lane-proto`
2. Add elements:
- Rectangle for background
- Text label for lane name
3. Style as desired (gradients, rounded corners, etc.)
4. Position at y=140 (will be translated for each lane)
### Step 4: Design Your Item Prototype
1. Create group named `item-proto`
2. Add elements:
- Shape (circle, rect, path) for marker
- Text elements for title, ID, or other fields
3. Give text elements IDs like `item-title`, `item-id`
4. Position at x=280, y=150
### Step 5: Add Containers
1. Create three empty groups:
- `months-container`
- `lanes-container`
- `items-container`
2. These can be anywhere - they're just containers
### Step 6: Add Styles
Use Inkscape's built-in styles or add a `<style>` section:
```xml
<defs>
<style>
.month-label { font-family: Arial; font-size: 11px; fill: #666; }
.lane-bg { fill: #f8f9fa; stroke: #e9ecef; }
.item-marker { fill: #007bff; }
</style>
</defs>
```
### Step 7: Save and Use
1. Save as Plain SVG (not Inkscape SVG)
2. Reference in your project.json:
```json
{
"svgTemplate": "template-proto.svg"
}
```
## Configuration Options
### Layout Settings
Control spacing and positioning in your project.json:
```json
{
"settings": {
"timelineMonths": 18,
"marginLeft": 220,
"marginTop": 140,
"monthWidth": 120,
"laneHeight": 80,
"laneGap": 16
}
}
```
- `marginLeft`: Left margin before first month
- `marginTop`: Top margin before first lane
- `monthWidth`: Horizontal space for each month
- `laneHeight`: Vertical space for each lane
- `laneGap`: Space between lanes
## Examples
### Example 1: Minimal Prototype Template
See `example-proto/template-proto.svg` for a complete working example.
### Example 2: Custom Styling
```xml
<g id="item-proto">
<rect x="-8" y="-8" width="16" height="16"
fill="#007bff" rx="3" opacity="0.8"/>
<text x="12" y="4"
font-family="Arial" font-size="10px" font-weight="bold">
Task Title
</text>
</g>
```
### Example 3: With Gradients
```xml
<defs>
<linearGradient id="laneGradient">
<stop offset="0%" stop-color="#ffffff"/>
<stop offset="100%" stop-color="#f0f0f0"/>
</linearGradient>
</defs>
<g id="lane-proto">
<rect fill="url(#laneGradient)" width="1000" height="80"/>
<text>Lane Name</text>
</g>
```
## Migration from Template-v2
If you have existing template-v2.svg files, you can continue using them. The generator automatically detects which template type you're using:
- **Prototype-based** (new): Detected by `id="*-proto"` elements → uses DOM generator
- **Template-v2** (old): Detected by `id="*-template"` elements → uses string generator
To migrate:
1. Open your template-v2.svg in Inkscape
2. Rename template elements:
- `month-template` → `month-proto`
- `lane-template` → `lane-proto`
- `item-template` → `item-proto`
3. Replace `{{PLACEHOLDERS}}` with actual sample text
4. Add IDs to text elements (e.g., `id="item-title"`)
5. Create container groups
6. Save and test
## Troubleshooting
### Prototypes Not Found
**Error:** `Template is missing required prototype elements`
**Solution:** Ensure your SVG has groups with exact IDs:
- `month-proto`
- `lane-proto`
- `item-proto`
Check Object Properties panel in Inkscape (Ctrl+Shift+O).
### Text Not Updating
**Problem:** Cloned items show placeholder text instead of data
**Solution:** Add IDs to text elements matching your field names:
```xml
<text id="item-title">Placeholder</text>
<text id="item-id">T-000</text>
```
### Wrong Positioning
**Problem:** Elements appear in wrong locations
**Solution:** Prototypes should be positioned at a base location (e.g., x=220 for months). The generator adds transforms for each clone. Check that your `marginLeft`, `marginTop`, `monthWidth`, etc. settings match your prototype positions.
### Styling Not Applied
**Problem:** Generated timeline doesn't have styles from Inkscape
**Solution:**
1. Use CSS classes in your prototypes, define in `<style>` section
2. Or use inline SVG attributes (fill, stroke, etc.)
3. Avoid Inkscape-specific attributes
### Parse Errors
**Error:** `Failed to parse SVG template`
**Solution:**
1. Save as "Plain SVG" not "Inkscape SVG"
2. Check SVG is valid XML (balanced tags, proper nesting)
3. Remove Inkscape-specific elements if present
## Best Practices
1. **Keep Prototypes Simple** - Complex nested structures may be harder to position
2. **Use CSS Classes** - Easier to style consistently than inline attributes
3. **Test Incrementally** - Start with basic shapes, add detail gradually
4. **Use Inkscape Layers** - Keep prototypes on separate layer for organization
5. **Set Prototype Opacity** - Makes them visible but distinguishable from final output
6. **Document Your Template** - Add comments or text notes explaining custom elements
## Advanced: Custom Field Mapping
You can map CSV columns to any text element IDs:
```json
{
"fieldMapping": {
"id": "ID",
"title": "Task Name",
"assignee": "Owner",
"status": "State"
}
}
```
Then in your prototype:
```xml
<g id="item-proto">
<text id="item-id">T-000</text>
<text id="item-title">Task placeholder</text>
<text id="item-assignee">Person</text>
<text id="item-status">Open</text>
</g>
```
## Further Resources
- See `example-proto/` for a complete working example
- Read `CLAUDE.md` for generator implementation details
- Check `README.md` for general usage instructions
## Comparison: Prototype vs Template-v2
| Feature | Prototype (New) | Template-v2 (Old) |
|---------|----------------|-------------------|
| Inkscape Editing | ✅ Full WYSIWYG | ⚠️ Limited (placeholders) |
| Valid SVG | ✅ Yes | ✅ Yes |
| Visual Preview | ✅ See actual design | ⚠️ See placeholders |
| Syntax | Simple IDs | `{{PLACEHOLDER}}` |
| Performance | ✅ DOM cloning | String manipulation |
| Styling | Full Inkscape tools | CSS + inline |
| Learning Curve | Lower (visual) | Higher (syntax) |
| Recommended | ✅ Yes | For legacy only |