feat: add inline file editing with modification tracking and save functionality

Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality.

Features:
- Edit buttons next to each file load button (Project, SVG, CSS, CSV)
- Modal editor with syntax validation for JSON files
- Real-time preview updates after applying changes
- Visual "MODIFIED" badges on edited files
- "Save Changes" button to download all modified files
- Keyboard shortcuts (Escape to close editor)

Implementation:
- file-editor.js: New module handling all editor functionality
  - Editor modal with textarea for content editing
  - Modification tracking using Set data structure
  - File-specific validation (JSON syntax checking)
  - Batch download of all modified files
  - Visual badge updates for modified state

- index.html: UI updates
  - Edit buttons added to all file items
  - Modal HTML structure for editor
  - Save Changes button in controls area
  - CSS styling for editor modal and modified badges

- engine.js: Integration and data storage
  - Store CSV and CSS content when loaded (for editing)
  - Enable edit buttons when files are successfully loaded
  - Works with all loading methods (folder picker, individual files, auto-load)
  - CSS now loaded via fetch to store content (changed from link href)

- Makefile: Include file-editor.js in distribution build

User workflow:
1. Load project files (folder picker or individual files)
2. Click "✏️ Edit" button next to any file
3. Make changes in modal editor
4. Click "Apply Changes" to update and see immediate preview
5. Modified files show orange "MODIFIED" badge
6. Click "💾 Save Changes" to download all modified files at once

Technical details:
- Edit buttons start disabled, enabled when file loads
- JSON validation prevents saving invalid configurations
- Changes apply immediately to in-memory data
- Timeline regenerates automatically after edits
- Modified state persists until files are saved
- Optional clearing of modified state after download

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-23 17:15:36 +01:00
parent cefbf96a82
commit 4576d066b3
4 changed files with 521 additions and 36 deletions

View File

@@ -49,6 +49,96 @@
background: #343a40;
}
.edit-btn {
background: #6c757d;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 11px;
cursor: pointer;
transition: background-color 0.2s;
border: none;
user-select: none;
}
.edit-btn:hover:not(:disabled) {
background: #545b62;
}
.edit-btn:disabled {
background: #e9ecef;
color: #adb5bd;
cursor: not-allowed;
}
.modified-badge {
display: inline-block;
background: #fd7e14;
color: white;
font-size: 9px;
padding: 2px 6px;
border-radius: 3px;
margin-left: 6px;
font-weight: 600;
}
.editor-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.6);
z-index: 10000;
padding: 20px;
overflow: auto;
}
.editor-content {
background: white;
max-width: 1200px;
margin: 0 auto;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
display: flex;
flex-direction: column;
max-height: 90vh;
}
.editor-header {
padding: 16px 20px;
border-bottom: 1px solid #dee2e6;
display: flex;
justify-content: space-between;
align-items: center;
}
.editor-body {
padding: 20px;
flex: 1;
overflow: auto;
}
.editor-textarea {
width: 100%;
min-height: 400px;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', monospace;
font-size: 13px;
padding: 12px;
border: 1px solid #ced4da;
border-radius: 4px;
resize: vertical;
}
.editor-footer {
padding: 16px 20px;
border-top: 1px solid #dee2e6;
display: flex;
gap: 12px;
justify-content: flex-end;
}
.file-status {
border-top: 1px solid #f1f3f4;
padding-top: 8px;
@@ -226,6 +316,7 @@
</style>
<script src="generator.js"></script>
<script src="engine.js"></script>
<script src="file-editor.js"></script>
</head>
<body class="internal-mode" style="font-family: Inter, Arial, sans-serif; background:#f5f7fa; margin:20px;">
@@ -260,10 +351,13 @@
<div class="file-item">
<div class="file-header">
<span class="file-label">Project Configuration</span>
<label class="upload-btn">
<input type="file" id="projectInput" accept=".json" style="display:none;" />
📁 Load
</label>
<div style="display:flex; gap:4px;">
<label class="upload-btn">
<input type="file" id="projectInput" accept=".json" style="display:none;" />
📁 Load
</label>
<button class="edit-btn" id="editProjectBtn" disabled>✏️ Edit</button>
</div>
</div>
<div class="file-status">
<span id="projectFile" class="file-name">Not loaded</span>
@@ -273,10 +367,13 @@
<div class="file-item">
<div class="file-header">
<span class="file-label">SVG Template</span>
<label class="upload-btn">
<input type="file" id="svgInput" accept=".svg" style="display:none;" />
🖼️ Load
</label>
<div style="display:flex; gap:4px;">
<label class="upload-btn">
<input type="file" id="svgInput" accept=".svg" style="display:none;" />
🖼️ Load
</label>
<button class="edit-btn" id="editSvgBtn" disabled>✏️ Edit</button>
</div>
</div>
<div class="file-status">
<span id="svgFile" class="file-name">Not loaded</span>
@@ -286,10 +383,13 @@
<div class="file-item">
<div class="file-header">
<span class="file-label">Stylesheet</span>
<label class="upload-btn">
<input type="file" id="cssInput" accept=".css" style="display:none;" />
🎨 Load
</label>
<div style="display:flex; gap:4px;">
<label class="upload-btn">
<input type="file" id="cssInput" accept=".css" style="display:none;" />
🎨 Load
</label>
<button class="edit-btn" id="editCssBtn" disabled>✏️ Edit</button>
</div>
</div>
<div class="file-status">
<span id="cssFile" class="file-name">Not loaded</span>
@@ -299,10 +399,13 @@
<div class="file-item">
<div class="file-header">
<span class="file-label">CSV Data</span>
<label class="upload-btn">
<input type="file" id="csvInput" accept=".csv" style="display:none;" />
📊 Load
</label>
<div style="display:flex; gap:4px;">
<label class="upload-btn">
<input type="file" id="csvInput" accept=".csv" style="display:none;" />
📊 Load
</label>
<button class="edit-btn" id="editCsvBtn" disabled>✏️ Edit</button>
</div>
</div>
<div class="file-status">
<span id="csvFile" class="file-name">Not loaded</span>
@@ -314,9 +417,13 @@
<button id="toggleView" style="padding:8px 16px; background:#495057; color:white; border:none; border-radius:6px; cursor:pointer; font-size:12px;">
🔄 Switch View (Internal / External)
</button>
<button id="saveChanges" disabled
style="padding:8px 16px; background:#28a745; color:white; border:none; border-radius:6px; cursor:pointer; opacity:0.6; font-size:12px;">
💾 Save Changes
</button>
<button id="downloadSvg" disabled
style="padding:8px 16px; background:#495057; color:white; border:none; border-radius:6px; cursor:pointer; opacity:0.6; font-size:12px;">
💾 Download SVG
📥 Download SVG
</button>
</div>
</div>
@@ -409,5 +516,26 @@
});
</script>
<!-- Editor Modal -->
<div id="editorModal" class="editor-modal">
<div class="editor-content">
<div class="editor-header">
<h3 id="editorTitle" style="margin:0; font-size:16px; font-weight:600;">Edit File</h3>
<button onclick="window.fileEditor.closeEditor()" style="background:none; border:none; font-size:24px; cursor:pointer; color:#6c757d;">×</button>
</div>
<div class="editor-body">
<textarea id="editorTextarea" class="editor-textarea" spellcheck="false"></textarea>
</div>
<div class="editor-footer">
<button onclick="window.fileEditor.closeEditor()" style="padding:8px 16px; background:#6c757d; color:white; border:none; border-radius:4px; cursor:pointer;">
Cancel
</button>
<button onclick="window.fileEditor.applyChanges()" style="padding:8px 16px; background:#007bff; color:white; border:none; border-radius:4px; cursor:pointer;">
Apply Changes
</button>
</div>
</div>
</div>
</body>
</html>