feat: ajout commentaires sur les fiches de la frise (fil de discussion E/M)

This commit is contained in:
2026-05-31 12:42:33 +00:00
parent fec391d7f3
commit b6a2514c45
+122
View File
@@ -172,6 +172,30 @@ window.dispatchEvent(new Event('tiptap-loaded'));
.like-btn:hover { color: var(--accent); transform: scale(1.15); }
.like-btn.liked { color: var(--terra); }
.like-btn .like-who { font-size: 10px; font-weight: 700; letter-spacing: 0.3px; }
.card-comment-count { font-size: 12px; color: var(--text-light); display: flex; align-items: center; gap: 3px; margin-left: 4px; }
.card-comment-count span { font-size: 13px; }
/* Comments in modal */
.modal-comments { border-top: 1px solid var(--border); padding-top: 16px; margin-top: 8px; }
.modal-comments h4 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--text-hint); font-weight: 600; margin-bottom: 12px; }
.comment-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; max-height: 240px; overflow-y: auto; }
.comment-item { background: var(--bg); border-radius: 8px; padding: 10px 14px; }
.comment-header { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.comment-author { font-size: 12px; font-weight: 700; }
.comment-author.e { color: var(--brown); }
.comment-author.m { color: var(--plum); }
.comment-date { font-size: 11px; color: var(--text-light); }
.comment-delete { margin-left: auto; background: none; border: none; font-size: 13px; color: var(--text-light); cursor: pointer; padding: 0 4px; }
.comment-delete:hover { color: #8b3030; }
.comment-text { font-size: 14px; color: var(--text); line-height: 1.5; }
.comment-add { display: flex; gap: 8px; align-items: flex-end; }
.comment-add textarea { flex: 1; padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px; font-size: 13px; font-family: 'Lora', serif; color: var(--text); background: var(--bg-input); resize: none; min-height: 36px; max-height: 80px; outline: none; }
.comment-add textarea:focus { border-color: var(--accent); }
.comment-add-btns { display: flex; flex-direction: column; gap: 4px; }
.comment-send { padding: 6px 12px; background: var(--accent); color: var(--bg); border: none; border-radius: 6px; font-size: 12px; font-weight: 600; font-family: 'Lora', serif; cursor: pointer; white-space: nowrap; }
.comment-send:hover { background: var(--accent-hover); }
.comment-author-toggle { padding: 4px 10px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; font-size: 11px; font-weight: 700; cursor: pointer; font-family: 'Lora', serif; color: var(--text-muted); }
.comment-author-toggle:hover { border-color: var(--accent); }
/* Acte colors on card top border */
.card[data-acte="Avant l'histoire"] { border-top-color: var(--blue-grey); }
@@ -616,6 +640,17 @@ window.dispatchEvent(new Event('tiptap-loaded'));
<label>Lien redaction</label>
<textarea id="f-lien" placeholder="Notes pour la redaction..."></textarea>
</div>
<div class="modal-comments" id="card-comments-section" style="display:none;">
<h4>Commentaires</h4>
<div class="comment-list" id="card-comment-list"></div>
<div class="comment-add">
<textarea id="card-comment-input" placeholder="Ajouter un commentaire..." rows="1" onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();addCardComment()}"></textarea>
<div class="comment-add-btns">
<button class="comment-send" onclick="addCardComment()">Envoyer</button>
<button class="comment-author-toggle" id="comment-author-btn" onclick="toggleCommentAuthor()">Etienne</button>
</div>
</div>
</div>
<div class="modal-actions">
<button class="btn-delete" id="btn-delete" onclick="deleteCard()" style="display:none;">Supprimer</button>
<button class="btn-save" onclick="saveCard()">Enregistrer</button>
@@ -750,6 +785,8 @@ function makeCard(r) {
const likeE = r.LikeE ? 'liked' : '';
const likeM = r.LikeM ? 'liked' : '';
const comments = parseComments(r.Commentaires);
const commentBadge = comments.length > 0 ? `<span class="card-comment-count"><span>&#9993;</span>${comments.length}</span>` : '';
card.innerHTML = `
<div class="card-title">${esc(r.Title || '')}</div>
@@ -758,6 +795,7 @@ function makeCard(r) {
${r.Statut ? `<span class="card-badge ${statusClass(r.Statut)}">${esc(r.Statut)}</span>` : ''}
${r.Type ? `<span class="card-badge badge-perso">${esc(r.Type)}</span>` : ''}
${persos}
${commentBadge}
<span class="card-likes">
<button class="like-btn ${likeE}" onclick="toggleLike(event,${r.Id},'E')" title="Etienne"><span class="like-who">E</span>&thinsp;&#9829;</button>
<button class="like-btn ${likeM}" onclick="toggleLike(event,${r.Id},'M')" title="Myriam"><span class="like-who">M</span>&thinsp;&#9829;</button>
@@ -782,6 +820,80 @@ async function toggleLike(e, id, who) {
});
}
// ── Card comments ──
let commentAuthor = 'E';
function parseComments(raw) {
if (!raw) return [];
try { return JSON.parse(raw); } catch { return []; }
}
function renderCardComments(comments) {
const list = document.getElementById('card-comment-list');
list.innerHTML = comments.map((c, i) => `
<div class="comment-item">
<div class="comment-header">
<span class="comment-author ${(c.auteur || 'E').toLowerCase()}">${c.auteur === 'M' ? 'Myriam' : 'Etienne'}</span>
<span class="comment-date">${esc(c.date || '')}</span>
<button class="comment-delete" onclick="deleteCardComment(${i})" title="Supprimer">&times;</button>
</div>
<div class="comment-text">${esc(c.texte || '')}</div>
</div>
`).join('');
}
async function addCardComment() {
if (!editingId) return;
const input = document.getElementById('card-comment-input');
const texte = input.value.trim();
if (!texte) return;
const r = records.find(r => r.Id === editingId);
if (!r) return;
const comments = parseComments(r.Commentaires);
const now = new Date().toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' });
comments.push({ auteur: commentAuthor, date: now, texte });
const json = JSON.stringify(comments);
r.Commentaires = json;
renderCardComments(comments);
input.value = '';
await fetch(`/api/records/${editingId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ Commentaires: json }),
});
renderFrise();
}
async function deleteCardComment(index) {
if (!editingId) return;
const r = records.find(r => r.Id === editingId);
if (!r) return;
const comments = parseComments(r.Commentaires);
comments.splice(index, 1);
const json = comments.length > 0 ? JSON.stringify(comments) : null;
r.Commentaires = json;
renderCardComments(comments);
await fetch(`/api/records/${editingId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ Commentaires: json || '' }),
});
renderFrise();
}
function toggleCommentAuthor() {
commentAuthor = commentAuthor === 'E' ? 'M' : 'E';
const btn = document.getElementById('comment-author-btn');
btn.textContent = commentAuthor === 'E' ? 'Etienne' : 'Myriam';
}
function renderFrise() {
const area = document.getElementById('timeline-area');
area.innerHTML = '';
@@ -950,6 +1062,9 @@ function openNew() {
document.getElementById('f-lien').value = '';
document.querySelectorAll('#f-perso .ms-tag').forEach(t => t.classList.remove('selected'));
document.getElementById('btn-delete').style.display = 'none';
document.getElementById('card-comments-section').style.display = 'none';
document.getElementById('card-comment-list').innerHTML = '';
document.getElementById('card-comment-input').value = '';
document.getElementById('modal').classList.add('open');
}
@@ -974,6 +1089,13 @@ function openEdit(id) {
});
document.getElementById('btn-delete').style.display = 'block';
// Comments
const comments = parseComments(r.Commentaires);
document.getElementById('card-comments-section').style.display = 'block';
renderCardComments(comments);
document.getElementById('card-comment-input').value = '';
document.getElementById('modal').classList.add('open');
}