dialog: Position/Rolle + Breadcrumb-Nav + nüchterne Wortmeldungen, Footer voll-breit
- comments: author_role (Position bei OPENBUREAU) aus authors.json gespeichert/ausgeliefert - schema: comments.author_role hinzugefügt - dialog.js: Breadcrumb (Dialoge › Forum), volles Datum/Uhrzeit, Box→Trennlinien-Layout - css: Footer voll-breit (Flex statt Grid), Balken zwischen Header/main/Footer entfernt Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+32
-13
@@ -28,6 +28,11 @@
|
||||
if (s < 86400) return Math.floor(s / 3600) + ' Std.';
|
||||
return d.toLocaleDateString('de-CH');
|
||||
}
|
||||
// Volles Datum + Uhrzeit (für die Wortmeldungen in der Thread-Ansicht).
|
||||
function fmtFull(ts) {
|
||||
const d = new Date(ts);
|
||||
return d.toLocaleDateString('de-CH') + ' · ' + d.toLocaleTimeString('de-CH', { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
const api = (p, opt) => fetch(p, opt).then(async (r) => ({ ok: r.ok, status: r.status, body: await r.json().catch(() => ({})) }));
|
||||
const authHdr = () => ({ Authorization: 'Bearer ' + token });
|
||||
|
||||
@@ -115,7 +120,7 @@
|
||||
// ── Forum-Ansicht: Threads + neuer Thread ─────────────────────────────────
|
||||
function renderForum(slug) {
|
||||
root.innerHTML = '';
|
||||
if (ctxEl) { ctxEl.innerHTML = ''; const b = el('a', null, '← Dialoge'); b.href = '/dialog/'; ctxEl.appendChild(b); }
|
||||
if (ctxEl) { ctxEl.innerHTML = ''; const c = el('nav', 'dialog-crumb'); const b = el('a', null, '← Dialoge'); b.href = '/dialog/'; c.appendChild(b); ctxEl.appendChild(c); }
|
||||
api('/api/forums/' + encodeURIComponent(slug)).then((r) => {
|
||||
if (!r.ok) { root.appendChild(el('p', 'dialog-empty', 'Forum nicht gefunden.')); return; }
|
||||
const { forum, threads } = r.body;
|
||||
@@ -192,9 +197,19 @@
|
||||
const m = r.body; title.textContent = m.title || 'Dialog'; locked = m.locked;
|
||||
if (ctxEl) {
|
||||
ctxEl.innerHTML = '';
|
||||
const back = el('a', null, m.kind === 'library' ? '← zum Beitrag' : (m.forum ? '← ' + m.forum.name : '← Dialoge'));
|
||||
back.href = m.kind === 'library' ? m.url : (m.forum ? '/dialog/?forum=' + encodeURIComponent(m.forum.slug) : '/dialog/');
|
||||
ctxEl.appendChild(back);
|
||||
if (m.kind === 'library') {
|
||||
const back = el('a', null, '← zum Beitrag'); back.href = m.url; ctxEl.appendChild(back);
|
||||
} else {
|
||||
// Breadcrumb-Navigation oben: Dialoge › Forum (beide anklickbar).
|
||||
const crumb = el('nav', 'dialog-crumb');
|
||||
const a0 = el('a', null, 'Dialoge'); a0.href = '/dialog/'; crumb.appendChild(a0);
|
||||
if (m.forum) {
|
||||
crumb.appendChild(el('span', 'dialog-crumb-sep', '›'));
|
||||
const a1 = el('a', null, m.forum.name); a1.href = '/dialog/?forum=' + encodeURIComponent(m.forum.slug);
|
||||
crumb.appendChild(a1);
|
||||
}
|
||||
ctxEl.appendChild(crumb);
|
||||
}
|
||||
}
|
||||
renderModbar(); renderComposer();
|
||||
});
|
||||
@@ -230,23 +245,27 @@
|
||||
const names = {}; data.forEach((c) => { names[c.id] = c.author_name; });
|
||||
if (!data.length) { list.appendChild(el('p', 'dialog-empty', 'Noch keine Wortmeldungen — beginne den Dialog.')); return; }
|
||||
data.forEach((c) => {
|
||||
const card = el('article', 'dialog-card');
|
||||
const head = el('header', 'dialog-card-head');
|
||||
// Nüchtern: Avatar · Name (+ Position) · darunter Datum/Uhrzeit · Text.
|
||||
const post = el('article', 'dialog-post');
|
||||
const head = el('header', 'dialog-post-head');
|
||||
const av = el('span', 'dialog-avatar');
|
||||
if (c.author_avatar) av.style.backgroundImage = 'url(' + c.author_avatar + ')';
|
||||
else av.textContent = (c.author_name || '?').slice(0, 1).toUpperCase();
|
||||
const meta = el('div', 'dialog-meta');
|
||||
meta.append(el('span', 'dialog-name', c.author_name || 'Unbekannt'), el('time', 'dialog-time', fmt(c.created_at)));
|
||||
if (c.parent_id && names[c.parent_id]) meta.appendChild(el('span', 'dialog-replyto', '↳ ' + names[c.parent_id]));
|
||||
head.append(av, meta); card.appendChild(head);
|
||||
card.appendChild(el('div', 'dialog-body', c.body));
|
||||
const ident = el('div', 'dialog-ident');
|
||||
const nameline = el('div', 'dialog-nameline');
|
||||
nameline.appendChild(el('span', 'dialog-name', c.author_name || 'Unbekannt'));
|
||||
if (c.author_role) nameline.appendChild(el('span', 'dialog-pos', c.author_role));
|
||||
if (c.parent_id && names[c.parent_id]) nameline.appendChild(el('span', 'dialog-replyto', '↳ ' + names[c.parent_id]));
|
||||
ident.append(nameline, el('time', 'dialog-time', fmtFull(c.created_at)));
|
||||
head.append(av, ident); post.appendChild(head);
|
||||
post.appendChild(el('div', 'dialog-body', c.body));
|
||||
if (token && !c.deleted) {
|
||||
const actions = el('div', 'dialog-actions');
|
||||
if (!locked) { const rep = el('button', null, 'Antworten'); rep.onclick = () => { replyTo = { id: c.id, name: c.author_name }; renderComposer(); if (textarea) textarea.focus(); }; actions.appendChild(rep); }
|
||||
const del = el('button', null, 'Löschen'); del.onclick = () => remove(c.id); actions.appendChild(del);
|
||||
card.appendChild(actions);
|
||||
post.appendChild(actions);
|
||||
}
|
||||
list.appendChild(card);
|
||||
list.appendChild(post);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user