@atlashub/smartstack-cli 4.22.0 → 4.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/skills/ba-design-ui/SKILL.md +91 -0
- package/templates/skills/ba-design-ui/steps/step-01-screens.md +177 -0
- package/templates/skills/ba-design-ui/steps/step-02-wireframes.md +140 -0
- package/templates/skills/ba-design-ui/steps/step-03-navigation.md +134 -0
- package/templates/skills/ba-generate-html/SKILL.md +0 -1
- package/templates/skills/ba-generate-html/html/ba-interactive.html +950 -1055
- package/templates/skills/ba-generate-html/html/src/scripts/01-data-init.js +1 -2
- package/templates/skills/ba-generate-html/html/src/scripts/02-navigation.js +0 -1
- package/templates/skills/ba-generate-html/html/src/scripts/03-render-cadrage.js +0 -39
- package/templates/skills/ba-generate-html/html/src/scripts/05-render-specs.js +0 -1
- package/templates/skills/ba-generate-html/html/src/scripts/07-render-handoff.js +0 -1
- package/templates/skills/ba-generate-html/html/src/scripts/08-editing.js +133 -135
- package/templates/skills/ba-generate-html/html/src/scripts/10-comments.js +199 -199
- package/templates/skills/ba-generate-html/html/src/scripts/11-review-panel.js +165 -166
- package/templates/skills/ba-generate-html/html/src/styles/05-modules.css +444 -454
- package/templates/skills/ba-generate-html/html/src/template.html +0 -49
- package/templates/skills/ba-generate-html/references/data-build.md +176 -182
- package/templates/skills/ba-generate-html/references/data-mapping.md +295 -299
- package/templates/skills/ba-generate-html/steps/step-01-collect.md +4 -22
- package/templates/skills/ba-generate-html/steps/step-02-build-data.md +2 -11
- package/templates/skills/ba-review/SKILL.md +16 -1
- package/templates/skills/ba-review/steps/step-01-apply.md +60 -10
- package/templates/skills/business-analyse/SKILL.md +19 -15
- package/templates/skills/business-analyse/steps/step-03-specify.md +9 -38
- package/templates/skills/derive-prd/SKILL.md +9 -9
- package/templates/skills/derive-prd/references/acceptance-criteria.md +166 -116
- package/templates/skills/derive-prd/references/entity-domain-mapping.md +5 -5
- package/templates/skills/derive-prd/references/handoff-file-templates.md +12 -12
- package/templates/skills/derive-prd/references/handoff-mappings.md +13 -14
- package/templates/skills/derive-prd/references/handoff-seeddata-generation.md +1 -1
- package/templates/skills/derive-prd/references/readiness-scoring.md +41 -50
- package/templates/skills/derive-prd/schemas/handoff-schema.json +2 -2
- package/templates/skills/derive-prd/steps/step-00-validate.md +73 -52
- package/templates/skills/derive-prd/steps/step-01-transform.md +86 -43
- package/templates/skills/ba-generate-html/html/src/partials/cadrage-risks.html +0 -48
|
@@ -1,199 +1,199 @@
|
|
|
1
|
-
/* ============================================
|
|
2
|
-
INLINE COMMENTS SYSTEM
|
|
3
|
-
============================================ */
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Comments are stored in data.comments[] with structure:
|
|
7
|
-
* { id, sectionId, cardIndex, author, timestamp, content, status, category }
|
|
8
|
-
*
|
|
9
|
-
* - sectionId: matches the section div id (e.g. "cadrage-problem", "module-spec-Clients")
|
|
10
|
-
* - cardIndex: index of the card within that section (0-based)
|
|
11
|
-
* - status: "to-review" | "validated"
|
|
12
|
-
* - category: "clarification" | "correction" | "suggestion"
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
function initInlineComments() {
|
|
16
|
-
// Cadrage sections: direct card children
|
|
17
|
-
document.querySelectorAll('.section > .card, .section > .stakeholder-card, .section > .uc-item
|
|
18
|
-
if (card.dataset.commentInitialized) return;
|
|
19
|
-
card.dataset.commentInitialized = 'true';
|
|
20
|
-
var section = card.closest('.section');
|
|
21
|
-
var sectionId = section ? section.id : 'unknown';
|
|
22
|
-
var siblings = Array.from(section.querySelectorAll(':scope > .card, :scope > .stakeholder-card, :scope > .uc-item
|
|
23
|
-
var index = siblings.indexOf(card);
|
|
24
|
-
card.appendChild(createCommentUI(sectionId, index));
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Module spec lists: nested items in ucList, brList, entList containers
|
|
28
|
-
document.querySelectorAll('[id^="ucList-"] > .uc-item, [id^="brList-"] > div, [id^="entList-"] > .entity-block').forEach(function(item) {
|
|
29
|
-
if (item.dataset.commentInitialized) return;
|
|
30
|
-
item.dataset.commentInitialized = 'true';
|
|
31
|
-
var list = item.parentElement;
|
|
32
|
-
var listId = list.id;
|
|
33
|
-
var siblings = Array.from(list.children);
|
|
34
|
-
var index = siblings.indexOf(item);
|
|
35
|
-
item.appendChild(createCommentUI(listId, index));
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Stakeholder cards in grid
|
|
39
|
-
document.querySelectorAll('.stakeholder-grid > .stakeholder-card').forEach(function(card) {
|
|
40
|
-
if (card.dataset.commentInitialized) return;
|
|
41
|
-
card.dataset.commentInitialized = 'true';
|
|
42
|
-
var grid = card.parentElement;
|
|
43
|
-
var section = card.closest('.section');
|
|
44
|
-
var sectionId = section ? section.id : 'stakeholders';
|
|
45
|
-
var siblings = Array.from(grid.children);
|
|
46
|
-
var index = siblings.indexOf(card);
|
|
47
|
-
card.appendChild(createCommentUI(sectionId, index));
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Scope items
|
|
51
|
-
['scopeVital', 'scopeImportant', 'scopeOptional', 'scopeExcluded'].forEach(function(containerId) {
|
|
52
|
-
var container = document.getElementById(containerId);
|
|
53
|
-
if (!container) return;
|
|
54
|
-
container.querySelectorAll('.uc-item').forEach(function(item, index) {
|
|
55
|
-
if (item.dataset.commentInitialized) return;
|
|
56
|
-
item.dataset.commentInitialized = 'true';
|
|
57
|
-
item.appendChild(createCommentUI(containerId, index));
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function createCommentUI(sectionId, cardIndex) {
|
|
63
|
-
const comments = getCommentsForCard(sectionId, cardIndex);
|
|
64
|
-
const count = comments.length;
|
|
65
|
-
|
|
66
|
-
const container = document.createElement('div');
|
|
67
|
-
container.className = 'comment-btn-container';
|
|
68
|
-
container.dataset.sectionId = sectionId;
|
|
69
|
-
container.dataset.cardIndex = cardIndex;
|
|
70
|
-
|
|
71
|
-
container.innerHTML = `
|
|
72
|
-
<button class="comment-toggle-btn" onclick="toggleCommentThread('${sectionId}', ${cardIndex})">
|
|
73
|
-
Commentaires <span class="comment-count ${count === 0 ? 'empty' : ''}">${count}</span>
|
|
74
|
-
</button>
|
|
75
|
-
<div class="comment-thread" id="comment-thread-${sectionId}-${cardIndex}">
|
|
76
|
-
<div class="comment-items" id="comment-items-${sectionId}-${cardIndex}">
|
|
77
|
-
${renderCommentItems(sectionId, cardIndex)}
|
|
78
|
-
</div>
|
|
79
|
-
<div class="comment-add-form">
|
|
80
|
-
<textarea id="comment-text-${sectionId}-${cardIndex}" placeholder="Ajouter un commentaire..."></textarea>
|
|
81
|
-
<select id="comment-cat-${sectionId}-${cardIndex}">
|
|
82
|
-
<option value="clarification">Clarification</option>
|
|
83
|
-
<option value="correction">Correction</option>
|
|
84
|
-
<option value="suggestion">Suggestion</option>
|
|
85
|
-
</select>
|
|
86
|
-
<button onclick="addInlineComment('${sectionId}', ${cardIndex})">Ajouter</button>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
`;
|
|
90
|
-
|
|
91
|
-
return container;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function getCommentsForCard(sectionId, cardIndex) {
|
|
95
|
-
return (data.comments || []).filter(c =>
|
|
96
|
-
c.sectionId === sectionId && c.cardIndex === cardIndex
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function toggleCommentThread(sectionId, cardIndex) {
|
|
101
|
-
const thread = document.getElementById('comment-thread-' + sectionId + '-' + cardIndex);
|
|
102
|
-
if (thread) thread.classList.toggle('visible');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function renderCommentItems(sectionId, cardIndex) {
|
|
106
|
-
const comments = getCommentsForCard(sectionId, cardIndex);
|
|
107
|
-
if (comments.length === 0) {
|
|
108
|
-
return '<div style="font-size:0.8rem;color:var(--text-muted);padding:0.5rem 0;font-style:italic;">Aucun commentaire</div>';
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return comments.map((c, i) => {
|
|
112
|
-
const initials = (c.author || 'U').substring(0, 2).toUpperCase();
|
|
113
|
-
const date = c.timestamp ? new Date(c.timestamp).toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }) : '';
|
|
114
|
-
const globalIndex = data.comments.indexOf(c);
|
|
115
|
-
|
|
116
|
-
return `
|
|
117
|
-
<div class="comment-item">
|
|
118
|
-
<div class="comment-avatar">${initials}</div>
|
|
119
|
-
<div class="comment-body">
|
|
120
|
-
<div class="comment-meta">
|
|
121
|
-
<span class="comment-author">${c.author || 'Utilisateur'}</span>
|
|
122
|
-
<span class="comment-date">${date}</span>
|
|
123
|
-
<span class="comment-category comment-category-${c.category}">${c.category}</span>
|
|
124
|
-
<span class="comment-status comment-status-${c.status}">${c.status === 'validated' ? 'Valide' : 'A revoir'}</span>
|
|
125
|
-
</div>
|
|
126
|
-
<div class="comment-text">${c.content}</div>
|
|
127
|
-
<div class="comment-actions">
|
|
128
|
-
<button class="comment-action-btn" onclick="toggleCommentStatus(${globalIndex})">${c.status === 'validated' ? 'Remettre a revoir' : 'Valider'}</button>
|
|
129
|
-
<button class="comment-action-btn" onclick="deleteComment(${globalIndex})" style="color:var(--error);">Supprimer</button>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
`;
|
|
134
|
-
}).join('');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function addInlineComment(sectionId, cardIndex) {
|
|
138
|
-
const textEl = document.getElementById('comment-text-' + sectionId + '-' + cardIndex);
|
|
139
|
-
const catEl = document.getElementById('comment-cat-' + sectionId + '-' + cardIndex);
|
|
140
|
-
const content = textEl.value.trim();
|
|
141
|
-
if (!content) return;
|
|
142
|
-
|
|
143
|
-
const comment = {
|
|
144
|
-
id: 'comment-' + Date.now(),
|
|
145
|
-
sectionId: sectionId,
|
|
146
|
-
cardIndex: cardIndex,
|
|
147
|
-
author: 'Utilisateur',
|
|
148
|
-
timestamp: new Date().toISOString(),
|
|
149
|
-
content: content,
|
|
150
|
-
status: 'to-review',
|
|
151
|
-
category: catEl.value
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
data.comments.push(comment);
|
|
155
|
-
textEl.value = '';
|
|
156
|
-
|
|
157
|
-
refreshCommentUI(sectionId, cardIndex);
|
|
158
|
-
renderReviewPanel();
|
|
159
|
-
autoSave();
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function toggleCommentStatus(globalIndex) {
|
|
163
|
-
const comment = data.comments[globalIndex];
|
|
164
|
-
if (!comment) return;
|
|
165
|
-
comment.status = comment.status === 'validated' ? 'to-review' : 'validated';
|
|
166
|
-
refreshCommentUI(comment.sectionId, comment.cardIndex);
|
|
167
|
-
renderReviewPanel();
|
|
168
|
-
autoSave();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function deleteComment(globalIndex) {
|
|
172
|
-
const comment = data.comments[globalIndex];
|
|
173
|
-
if (!comment) return;
|
|
174
|
-
const sectionId = comment.sectionId;
|
|
175
|
-
const cardIndex = comment.cardIndex;
|
|
176
|
-
data.comments.splice(globalIndex, 1);
|
|
177
|
-
refreshCommentUI(sectionId, cardIndex);
|
|
178
|
-
renderReviewPanel();
|
|
179
|
-
autoSave();
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function refreshCommentUI(sectionId, cardIndex) {
|
|
183
|
-
// Update comment items
|
|
184
|
-
const itemsContainer = document.getElementById('comment-items-' + sectionId + '-' + cardIndex);
|
|
185
|
-
if (itemsContainer) {
|
|
186
|
-
itemsContainer.innerHTML = renderCommentItems(sectionId, cardIndex);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Update count badge
|
|
190
|
-
const count = getCommentsForCard(sectionId, cardIndex).length;
|
|
191
|
-
const container = document.querySelector(`.comment-btn-container[data-section-id="${sectionId}"][data-card-index="${cardIndex}"]`);
|
|
192
|
-
if (container) {
|
|
193
|
-
const badge = container.querySelector('.comment-count');
|
|
194
|
-
if (badge) {
|
|
195
|
-
badge.textContent = count;
|
|
196
|
-
badge.className = 'comment-count' + (count === 0 ? ' empty' : '');
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
1
|
+
/* ============================================
|
|
2
|
+
INLINE COMMENTS SYSTEM
|
|
3
|
+
============================================ */
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Comments are stored in data.comments[] with structure:
|
|
7
|
+
* { id, sectionId, cardIndex, author, timestamp, content, status, category }
|
|
8
|
+
*
|
|
9
|
+
* - sectionId: matches the section div id (e.g. "cadrage-problem", "module-spec-Clients")
|
|
10
|
+
* - cardIndex: index of the card within that section (0-based)
|
|
11
|
+
* - status: "to-review" | "validated"
|
|
12
|
+
* - category: "clarification" | "correction" | "suggestion"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
function initInlineComments() {
|
|
16
|
+
// Cadrage sections: direct card children
|
|
17
|
+
document.querySelectorAll('.section > .card, .section > .stakeholder-card, .section > .uc-item').forEach(function(card) {
|
|
18
|
+
if (card.dataset.commentInitialized) return;
|
|
19
|
+
card.dataset.commentInitialized = 'true';
|
|
20
|
+
var section = card.closest('.section');
|
|
21
|
+
var sectionId = section ? section.id : 'unknown';
|
|
22
|
+
var siblings = Array.from(section.querySelectorAll(':scope > .card, :scope > .stakeholder-card, :scope > .uc-item'));
|
|
23
|
+
var index = siblings.indexOf(card);
|
|
24
|
+
card.appendChild(createCommentUI(sectionId, index));
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Module spec lists: nested items in ucList, brList, entList containers
|
|
28
|
+
document.querySelectorAll('[id^="ucList-"] > .uc-item, [id^="brList-"] > div, [id^="entList-"] > .entity-block').forEach(function(item) {
|
|
29
|
+
if (item.dataset.commentInitialized) return;
|
|
30
|
+
item.dataset.commentInitialized = 'true';
|
|
31
|
+
var list = item.parentElement;
|
|
32
|
+
var listId = list.id;
|
|
33
|
+
var siblings = Array.from(list.children);
|
|
34
|
+
var index = siblings.indexOf(item);
|
|
35
|
+
item.appendChild(createCommentUI(listId, index));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Stakeholder cards in grid
|
|
39
|
+
document.querySelectorAll('.stakeholder-grid > .stakeholder-card').forEach(function(card) {
|
|
40
|
+
if (card.dataset.commentInitialized) return;
|
|
41
|
+
card.dataset.commentInitialized = 'true';
|
|
42
|
+
var grid = card.parentElement;
|
|
43
|
+
var section = card.closest('.section');
|
|
44
|
+
var sectionId = section ? section.id : 'stakeholders';
|
|
45
|
+
var siblings = Array.from(grid.children);
|
|
46
|
+
var index = siblings.indexOf(card);
|
|
47
|
+
card.appendChild(createCommentUI(sectionId, index));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Scope items
|
|
51
|
+
['scopeVital', 'scopeImportant', 'scopeOptional', 'scopeExcluded'].forEach(function(containerId) {
|
|
52
|
+
var container = document.getElementById(containerId);
|
|
53
|
+
if (!container) return;
|
|
54
|
+
container.querySelectorAll('.uc-item').forEach(function(item, index) {
|
|
55
|
+
if (item.dataset.commentInitialized) return;
|
|
56
|
+
item.dataset.commentInitialized = 'true';
|
|
57
|
+
item.appendChild(createCommentUI(containerId, index));
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function createCommentUI(sectionId, cardIndex) {
|
|
63
|
+
const comments = getCommentsForCard(sectionId, cardIndex);
|
|
64
|
+
const count = comments.length;
|
|
65
|
+
|
|
66
|
+
const container = document.createElement('div');
|
|
67
|
+
container.className = 'comment-btn-container';
|
|
68
|
+
container.dataset.sectionId = sectionId;
|
|
69
|
+
container.dataset.cardIndex = cardIndex;
|
|
70
|
+
|
|
71
|
+
container.innerHTML = `
|
|
72
|
+
<button class="comment-toggle-btn" onclick="toggleCommentThread('${sectionId}', ${cardIndex})">
|
|
73
|
+
Commentaires <span class="comment-count ${count === 0 ? 'empty' : ''}">${count}</span>
|
|
74
|
+
</button>
|
|
75
|
+
<div class="comment-thread" id="comment-thread-${sectionId}-${cardIndex}">
|
|
76
|
+
<div class="comment-items" id="comment-items-${sectionId}-${cardIndex}">
|
|
77
|
+
${renderCommentItems(sectionId, cardIndex)}
|
|
78
|
+
</div>
|
|
79
|
+
<div class="comment-add-form">
|
|
80
|
+
<textarea id="comment-text-${sectionId}-${cardIndex}" placeholder="Ajouter un commentaire..."></textarea>
|
|
81
|
+
<select id="comment-cat-${sectionId}-${cardIndex}">
|
|
82
|
+
<option value="clarification">Clarification</option>
|
|
83
|
+
<option value="correction">Correction</option>
|
|
84
|
+
<option value="suggestion">Suggestion</option>
|
|
85
|
+
</select>
|
|
86
|
+
<button onclick="addInlineComment('${sectionId}', ${cardIndex})">Ajouter</button>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
return container;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getCommentsForCard(sectionId, cardIndex) {
|
|
95
|
+
return (data.comments || []).filter(c =>
|
|
96
|
+
c.sectionId === sectionId && c.cardIndex === cardIndex
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function toggleCommentThread(sectionId, cardIndex) {
|
|
101
|
+
const thread = document.getElementById('comment-thread-' + sectionId + '-' + cardIndex);
|
|
102
|
+
if (thread) thread.classList.toggle('visible');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function renderCommentItems(sectionId, cardIndex) {
|
|
106
|
+
const comments = getCommentsForCard(sectionId, cardIndex);
|
|
107
|
+
if (comments.length === 0) {
|
|
108
|
+
return '<div style="font-size:0.8rem;color:var(--text-muted);padding:0.5rem 0;font-style:italic;">Aucun commentaire</div>';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return comments.map((c, i) => {
|
|
112
|
+
const initials = (c.author || 'U').substring(0, 2).toUpperCase();
|
|
113
|
+
const date = c.timestamp ? new Date(c.timestamp).toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }) : '';
|
|
114
|
+
const globalIndex = data.comments.indexOf(c);
|
|
115
|
+
|
|
116
|
+
return `
|
|
117
|
+
<div class="comment-item">
|
|
118
|
+
<div class="comment-avatar">${initials}</div>
|
|
119
|
+
<div class="comment-body">
|
|
120
|
+
<div class="comment-meta">
|
|
121
|
+
<span class="comment-author">${c.author || 'Utilisateur'}</span>
|
|
122
|
+
<span class="comment-date">${date}</span>
|
|
123
|
+
<span class="comment-category comment-category-${c.category}">${c.category}</span>
|
|
124
|
+
<span class="comment-status comment-status-${c.status}">${c.status === 'validated' ? 'Valide' : 'A revoir'}</span>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="comment-text">${c.content}</div>
|
|
127
|
+
<div class="comment-actions">
|
|
128
|
+
<button class="comment-action-btn" onclick="toggleCommentStatus(${globalIndex})">${c.status === 'validated' ? 'Remettre a revoir' : 'Valider'}</button>
|
|
129
|
+
<button class="comment-action-btn" onclick="deleteComment(${globalIndex})" style="color:var(--error);">Supprimer</button>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
`;
|
|
134
|
+
}).join('');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function addInlineComment(sectionId, cardIndex) {
|
|
138
|
+
const textEl = document.getElementById('comment-text-' + sectionId + '-' + cardIndex);
|
|
139
|
+
const catEl = document.getElementById('comment-cat-' + sectionId + '-' + cardIndex);
|
|
140
|
+
const content = textEl.value.trim();
|
|
141
|
+
if (!content) return;
|
|
142
|
+
|
|
143
|
+
const comment = {
|
|
144
|
+
id: 'comment-' + Date.now(),
|
|
145
|
+
sectionId: sectionId,
|
|
146
|
+
cardIndex: cardIndex,
|
|
147
|
+
author: 'Utilisateur',
|
|
148
|
+
timestamp: new Date().toISOString(),
|
|
149
|
+
content: content,
|
|
150
|
+
status: 'to-review',
|
|
151
|
+
category: catEl.value
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
data.comments.push(comment);
|
|
155
|
+
textEl.value = '';
|
|
156
|
+
|
|
157
|
+
refreshCommentUI(sectionId, cardIndex);
|
|
158
|
+
renderReviewPanel();
|
|
159
|
+
autoSave();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function toggleCommentStatus(globalIndex) {
|
|
163
|
+
const comment = data.comments[globalIndex];
|
|
164
|
+
if (!comment) return;
|
|
165
|
+
comment.status = comment.status === 'validated' ? 'to-review' : 'validated';
|
|
166
|
+
refreshCommentUI(comment.sectionId, comment.cardIndex);
|
|
167
|
+
renderReviewPanel();
|
|
168
|
+
autoSave();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function deleteComment(globalIndex) {
|
|
172
|
+
const comment = data.comments[globalIndex];
|
|
173
|
+
if (!comment) return;
|
|
174
|
+
const sectionId = comment.sectionId;
|
|
175
|
+
const cardIndex = comment.cardIndex;
|
|
176
|
+
data.comments.splice(globalIndex, 1);
|
|
177
|
+
refreshCommentUI(sectionId, cardIndex);
|
|
178
|
+
renderReviewPanel();
|
|
179
|
+
autoSave();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function refreshCommentUI(sectionId, cardIndex) {
|
|
183
|
+
// Update comment items
|
|
184
|
+
const itemsContainer = document.getElementById('comment-items-' + sectionId + '-' + cardIndex);
|
|
185
|
+
if (itemsContainer) {
|
|
186
|
+
itemsContainer.innerHTML = renderCommentItems(sectionId, cardIndex);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Update count badge
|
|
190
|
+
const count = getCommentsForCard(sectionId, cardIndex).length;
|
|
191
|
+
const container = document.querySelector(`.comment-btn-container[data-section-id="${sectionId}"][data-card-index="${cardIndex}"]`);
|
|
192
|
+
if (container) {
|
|
193
|
+
const badge = container.querySelector('.comment-count');
|
|
194
|
+
if (badge) {
|
|
195
|
+
badge.textContent = count;
|
|
196
|
+
badge.className = 'comment-count' + (count === 0 ? ' empty' : '');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|