diff --git a/public/index.html b/public/index.html
index 59c5af6..7f18121 100644
--- a/public/index.html
+++ b/public/index.html
@@ -14,9 +14,9 @@ const Comment = Mark.create({
name: 'comment',
addAttributes() {
return {
- text: { default: '' },
- author: { default: 'E' },
- date: { default: '' },
+ text: { default: '', parseHTML: el => el.getAttribute('data-comment') || '' },
+ author: { default: 'E', parseHTML: el => el.getAttribute('data-author') || 'E' },
+ date: { default: '', parseHTML: el => el.getAttribute('data-date') || '' },
};
},
parseHTML() {
@@ -177,13 +177,12 @@ window.dispatchEvent(new Event('tiptap-loaded'));
.card[data-acte="En attente"] { border-top-color: var(--border); }
/* Status badge colors */
- .badge-germe { background: var(--border); color: var(--text-muted); }
+ .badge-validee { background: #eef3e8; color: #5a7a3a; }
.badge-etudier { background: #f5f0e4; color: #a07850; }
- .badge-posee { background: #eef3e8; color: #5a7a3a; }
.badge-abandonnee { background: var(--border); color: var(--text-hint); text-decoration: line-through; }
.badge-conflit { background: #f5e4e4; color: #8b3030; }
.dark .badge-etudier { background: #3a3020; color: #c49860; }
- .dark .badge-posee { background: #2a3520; color: #8aaa6a; }
+ .dark .badge-validee { background: #2a3520; color: #8aaa6a; }
.dark .badge-conflit { background: #3a2020; color: #c06060; }
.badge-perso { background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); }
@@ -217,6 +216,8 @@ window.dispatchEvent(new Event('tiptap-loaded'));
.multi-select-container { display: flex; flex-wrap: wrap; gap: 5px; padding: 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-input); min-height: 38px; }
.multi-select-container .ms-tag { font-size: 12px; padding: 3px 9px; border-radius: 6px; background: var(--border); color: var(--text-muted); cursor: pointer; }
.multi-select-container .ms-tag.selected { background: var(--accent); color: var(--bg); }
+ .multi-select-container .ms-add { font-size: 12px; padding: 3px 9px; border-radius: 6px; background: transparent; border: 1px dashed var(--border); color: var(--text-hint); cursor: pointer; }
+ .multi-select-container .ms-add:hover { border-color: var(--accent); color: var(--accent); }
.modal-actions { display: flex; gap: 10px; justify-content: space-between; margin-top: 8px; }
.btn-save { padding: 9px 22px; background: var(--accent); color: var(--bg); border: none; border-radius: 8px; font-size: 14px; font-weight: 600; font-family: 'Lora', serif; cursor: pointer; }
.btn-save:hover { background: var(--accent-hover); }
@@ -720,8 +721,8 @@ function clearFilters() {
const statusClass = s => {
if (!s) return '';
- const map = { 'Germe': 'badge-germe', 'À étudier': 'badge-etudier', 'Posée': 'badge-posee', 'Abandonnée': 'badge-abandonnee', 'En conflit': 'badge-conflit' };
- return map[s] || 'badge-germe';
+ const map = { 'À étudier': 'badge-etudier', 'Validée': 'badge-validee', 'Abandonnée': 'badge-abandonnee', 'En conflit': 'badge-conflit' };
+ return map[s] || 'badge-etudier';
};
function makeCard(r) {
@@ -870,6 +871,36 @@ function populateSelects() {
container.appendChild(tag);
});
}
+ const addBtn = document.createElement('span');
+ addBtn.className = 'ms-add';
+ addBtn.textContent = '+';
+ addBtn.title = 'Ajouter un personnage';
+ addBtn.onclick = async () => {
+ const name = prompt('Nom du personnage :');
+ if (!name || !name.trim()) return;
+ const trimmed = name.trim();
+ if (columns.Personnage && columns.Personnage.options.includes(trimmed)) {
+ alert('Ce personnage existe déjà.');
+ return;
+ }
+ const res = await fetch('/api/columns/personnage', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ name: trimmed }),
+ });
+ if (res.ok) {
+ if (!columns.Personnage) columns.Personnage = { type: 'MultiSelect', options: [] };
+ columns.Personnage.options.push(trimmed);
+ const tag = document.createElement('span');
+ tag.className = 'ms-tag selected';
+ tag.textContent = trimmed;
+ tag.onclick = () => tag.classList.toggle('selected');
+ container.insertBefore(tag, addBtn);
+ } else {
+ alert('Erreur lors de l\'ajout.');
+ }
+ };
+ container.appendChild(addBtn);
}
function openNew() {
@@ -877,7 +908,7 @@ function openNew() {
document.getElementById('modal-label').textContent = 'Nouvelle idee';
document.getElementById('f-title').value = '';
document.getElementById('f-type').value = '';
- document.getElementById('f-statut').value = 'Germe';
+ document.getElementById('f-statut').value = 'À étudier';
document.getElementById('f-acte').value = 'En attente';
document.getElementById('f-resume').value = '';
document.getElementById('f-interet').value = '';
diff --git a/server.js b/server.js
index 8245e5f..fa94ed8 100644
--- a/server.js
+++ b/server.js
@@ -126,6 +126,33 @@ app.get('/api/columns', requireAuth, async (req, res) => {
}
});
+// Add a new Personnage option
+app.post('/api/columns/personnage', requireAuth, async (req, res) => {
+ try {
+ const { name } = req.body;
+ if (!name) return res.status(400).json({ error: 'Nom requis' });
+ // Get current column meta
+ const metaUrl = `${NOCODB_URL}/api/v2/meta/tables/${NOCODB_TABLE_ID}`;
+ const metaRes = await fetch(metaUrl, { headers: { 'xc-token': NOCODB_TOKEN } });
+ const table = await metaRes.json();
+ const col = table.columns.find(c => c.title === 'Personnage');
+ if (!col) return res.status(404).json({ error: 'Colonne Personnage introuvable' });
+ const options = col.colOptions?.options || [];
+ if (options.some(o => o.title === name)) return res.status(409).json({ error: 'Existe déjà' });
+ options.push({ title: name });
+ const patchUrl = `${NOCODB_URL}/api/v2/meta/columns/${col.id}`;
+ const patchRes = await fetch(patchUrl, {
+ method: 'PATCH',
+ headers: { 'xc-token': NOCODB_TOKEN, 'Content-Type': 'application/json' },
+ body: JSON.stringify({ colOptions: { options } }),
+ });
+ if (!patchRes.ok) return res.status(500).json({ error: 'Erreur NocoDB' });
+ res.json({ ok: true });
+ } catch (e) {
+ res.status(500).json({ error: e.message });
+ }
+});
+
// Bulk update order (for drag-and-drop)
app.post('/api/reorder', requireAuth, async (req, res) => {
try {