Locations können nun auch Posten - bugfixes im Feed
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
<title>Home – xXx Sphere</title>
|
||||
<link rel="stylesheet" href="/css/variables.css">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="stylesheet" href="/css/community.css">
|
||||
<style>
|
||||
.game-grid {
|
||||
display: grid;
|
||||
@@ -184,64 +185,9 @@
|
||||
}
|
||||
.friend-req-badge { font-size: 0.65rem; color: var(--color-primary); font-weight: 600; text-align: center; }
|
||||
|
||||
/* ── Compose ── */
|
||||
.post-compose { background:var(--color-card); border:1px solid var(--color-secondary); border-radius:10px; padding:1rem; margin-bottom:1rem; transition:border-color 0.15s; }
|
||||
.post-compose.drag-over { border-color:var(--color-primary); background:rgba(var(--color-primary-rgb,180,0,60),0.06); }
|
||||
.compose-type { display:flex; gap:1.5rem; margin-bottom:0.75rem; }
|
||||
.compose-type label { display:flex; align-items:center; gap:0.4rem; font-size:0.9rem; cursor:pointer; }
|
||||
.post-compose textarea { width:100%; padding:0.6rem 0.85rem; border:1px solid var(--color-secondary); border-radius:6px; background:var(--color-secondary); color:var(--color-text); font-size:0.95rem; outline:none; transition:border-color 0.2s; resize:vertical; min-height:70px; box-sizing:border-box; }
|
||||
.post-compose textarea:focus { border-color:var(--color-primary); }
|
||||
.compose-thumbs { display:none; flex-wrap:wrap; gap:0.5rem; margin-top:0.5rem; }
|
||||
.compose-thumb { position:relative; width:64px; height:64px; flex-shrink:0; }
|
||||
.compose-thumb img { width:64px; height:64px; object-fit:cover; border-radius:6px; display:block; }
|
||||
.compose-thumb-remove { position:absolute; top:-5px; right:-5px; background:rgba(0,0,0,0.7); border:none; color:#fff; border-radius:50%; font-size:0.65rem; cursor:pointer; display:flex; align-items:center; justify-content:center; padding:0; margin:0; width:auto; line-height:1; }
|
||||
.umfrage-options { margin-top:0.5rem; }
|
||||
.umfrage-option-row { display:flex; gap:0.5rem; margin-bottom:0.4rem; }
|
||||
.umfrage-option-row input { flex:1; }
|
||||
.umfrage-option-row button { width:auto; margin:0; padding:0.3rem 0.6rem; font-size:0.8rem; }
|
||||
.compose-footer { display:flex; justify-content:space-between; align-items:center; margin-top:0.75rem; flex-wrap:wrap; gap:0.5rem; }
|
||||
.multi-toggle { font-size:0.85rem; display:flex; align-items:center; gap:0.4rem; }
|
||||
.privacy-toggle { font-size:0.85rem; display:flex; align-items:center; gap:0.4rem; }
|
||||
.compose-action-btn { background:none; border:1px solid var(--color-secondary); color:var(--color-muted); border-radius:6px; padding:0.35rem 0.6rem; font-size:0.95rem; cursor:pointer; margin:0; width:auto; transition:border-color 0.15s,color 0.15s; }
|
||||
.compose-action-btn:hover { border-color:var(--color-primary); color:var(--color-primary); background:none; }
|
||||
label.compose-action-btn { display:inline-flex; align-items:center; }
|
||||
|
||||
/* ── Post Cards (1:1 wie Feed) ── */
|
||||
.post-card { background:var(--color-card); border:1px solid var(--color-secondary); border-radius:10px; padding:1rem; margin-bottom:0.9rem; cursor:pointer; transition:border-color 0.15s; }
|
||||
/* ── Post-Cards (Home: klickbar + Hover) ── */
|
||||
.post-card { cursor:pointer; transition:border-color 0.15s; }
|
||||
.post-card:hover { border-color:var(--color-primary); }
|
||||
.post-header { display:flex; align-items:center; gap:0.7rem; margin-bottom:0.6rem; }
|
||||
.post-avatar { width:36px; height:36px; border-radius:50%; background:var(--color-secondary); display:flex; align-items:center; justify-content:center; font-size:0.95rem; flex-shrink:0; overflow:hidden; }
|
||||
.post-avatar img { width:100%; height:100%; object-fit:cover; }
|
||||
.post-author { font-weight:600; font-size:0.9rem; }
|
||||
.post-meta { font-size:0.75rem; color:var(--color-muted); }
|
||||
.post-text { font-size:0.95rem; line-height:1.5; white-space:pre-wrap; word-break:break-word; }
|
||||
.post-bild { width:100%; max-height:400px; object-fit:contain; border-radius:6px; margin-top:0.5rem; display:block; }
|
||||
.post-actions { display:flex; gap:1rem; margin-top:0.75rem; align-items:center; flex-wrap:wrap; }
|
||||
.post-action-btn { background:none; border:none; color:var(--color-muted); font-size:0.85rem; padding:0; display:flex; align-items:center; gap:0.3rem; margin:0; width:auto; pointer-events:none; }
|
||||
.post-action-btn.active { color:var(--color-primary); }
|
||||
.gruppe-badge { display:inline-flex; align-items:center; gap:0.3rem; font-size:0.75rem; color:var(--color-muted); background:var(--color-secondary); border-radius:4px; padding:0.15rem 0.45rem; margin-left:0.3rem; }
|
||||
.umfrage-option-bar { margin:0.3rem 0; border-radius:6px; overflow:hidden; border:1px solid var(--color-secondary); position:relative; }
|
||||
.umfrage-option-bar.voted { border-color:var(--color-primary); }
|
||||
.umfrage-bar-fill { position:absolute; inset:0; background:rgba(var(--color-primary-rgb,180,0,60),0.15); }
|
||||
.umfrage-bar-content { position:relative; display:flex; justify-content:space-between; padding:0.45rem 0.75rem; font-size:0.88rem; }
|
||||
.umfrage-total { font-size:0.78rem; color:var(--color-muted); margin-top:0.3rem; }
|
||||
|
||||
/* ── Post Lightbox ── */
|
||||
.lightbox { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.88); z-index:300; align-items:center; justify-content:center; }
|
||||
.lightbox.open { display:flex; }
|
||||
.lb-layout { display:flex; max-width:min(1340px, calc(100vw - 2rem)); width:95vw; height:min(90vh, 1100px); background:var(--color-card); border-radius:12px; overflow:hidden; position:relative; }
|
||||
.lb-post-side { flex:1; overflow-y:auto; padding:1.25rem; border-right:1px solid var(--color-secondary); min-width:0; }
|
||||
.lb-post-side .post-bild { max-height:1024px; }
|
||||
.lb-close { position:absolute; top:0.6rem; right:0.6rem; background:rgba(0,0,0,0.55); border:none; color:#fff; font-size:1.1rem; width:2rem; height:2rem; border-radius:50%; cursor:pointer; z-index:10; display:flex; align-items:center; justify-content:center; padding:0; margin:0; }
|
||||
.lb-comments-panel { width:300px; flex-shrink:0; display:flex; flex-direction:column; }
|
||||
.lb-comments-header { font-size:0.78rem; font-weight:600; color:var(--color-muted); text-transform:uppercase; letter-spacing:0.06em; padding:0.7rem 1rem; border-bottom:1px solid var(--color-secondary); flex-shrink:0; }
|
||||
.lb-comments-list { flex:1; overflow-y:auto; padding:0.75rem; }
|
||||
.lb-comment-compose { padding:0.75rem; border-top:1px solid var(--color-secondary); display:flex; flex-direction:column; gap:0.5rem; flex-shrink:0; }
|
||||
.lb-comment-compose textarea { width:100%; font-size:0.85rem; padding:0.35rem 0.6rem; resize:none; background:var(--color-secondary); border:1px solid var(--color-secondary); border-radius:6px; color:var(--color-text); font-family:inherit; outline:none; transition:border-color 0.2s; box-sizing:border-box; }
|
||||
.lb-comment-compose textarea:focus { border-color:var(--color-primary); }
|
||||
.lb-comment-compose-actions { display:flex; gap:0.5rem; justify-content:flex-end; }
|
||||
.lb-comment-compose button { width:auto; margin:0; padding:0.35rem 0.75rem; font-size:0.8rem; }
|
||||
@media (max-width:650px) { .lb-layout { flex-direction:column; height:95vh; } .lb-post-side { border-right:none; border-bottom:1px solid var(--color-secondary); max-height:55vh; } .lb-comments-panel { width:100%; } }
|
||||
|
||||
/* ── Spiel starten ── */
|
||||
.start-game-grid {
|
||||
@@ -413,21 +359,19 @@
|
||||
<!-- Feed Compose + Vorschau -->
|
||||
<div class="section-label">Feed 📰</div>
|
||||
<div class="post-compose" id="homeCompose">
|
||||
<div class="compose-type">
|
||||
<label><input type="radio" name="homeBeitragTyp" value="TEXT" checked onchange="homeToggleUmfrage()"> Text</label>
|
||||
<label><input type="radio" name="homeBeitragTyp" value="UMFRAGE" onchange="homeToggleUmfrage()"> Umfrage</label>
|
||||
</div>
|
||||
<textarea id="homeComposeText" placeholder="Was möchtest du teilen?" rows="3"></textarea>
|
||||
<div class="compose-thumbs" id="homeComposeThumbs"></div>
|
||||
<div class="umfrage-options" id="homeUmfrageOptions" style="display:none;">
|
||||
<div id="homeOptionList"></div>
|
||||
<button onclick="homeAddOption()" style="width:auto;margin:0;padding:0.3rem 0.75rem;font-size:0.8rem;margin-top:0.4rem;">+ Option</button>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:0.5rem;">
|
||||
<button onclick="homeAddOption()" style="width:auto;margin:0;padding:0.3rem 0.75rem;font-size:0.8rem;">+ Option</button>
|
||||
<label class="multi-toggle">
|
||||
<input type="checkbox" id="homeMultiChoice"> Mehrfachauswahl möglich
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="compose-footer">
|
||||
<div style="display:flex;gap:1rem;align-items:center;flex-wrap:wrap;">
|
||||
<label class="multi-toggle" id="homeMultiChoiceRow" style="display:none;">
|
||||
<input type="checkbox" id="homeMultiChoice"> Multi-Choice
|
||||
</label>
|
||||
<label class="privacy-toggle">
|
||||
<input type="checkbox" id="homeIsPublic"> Öffentlich
|
||||
</label>
|
||||
@@ -437,6 +381,7 @@
|
||||
<label class="compose-action-btn" title="Fotos hinzufügen">📷
|
||||
<input type="file" id="homeComposeBildFile" accept="image/*" multiple style="display:none;" onchange="homeSelectBilder(this)">
|
||||
</label>
|
||||
<button type="button" id="homeUmfrageBtn" class="compose-action-btn" onclick="homeToggleUmfrage(this)" title="Umfrage hinzufügen">📊</button>
|
||||
<button onclick="homeSubmitPost()" style="width:auto;margin:0;">Veröffentlichen</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -482,6 +427,7 @@
|
||||
.then(user => {
|
||||
if (user) {
|
||||
myUserId = user.userId;
|
||||
initLb(user.userId);
|
||||
document.getElementById('greeting').textContent = 'Willkommen zurück, ' + user.name + '!';
|
||||
Promise.all([loadActiveGames(user.userId), loadActiveLock()]).then(() => {
|
||||
const hasGames = document.getElementById('activeGamesSection').style.display !== 'none';
|
||||
@@ -770,15 +716,22 @@
|
||||
|
||||
let homeComposeBilder = [];
|
||||
|
||||
function homeToggleUmfrage() {
|
||||
const isUmfrage = document.querySelector('input[name="homeBeitragTyp"]:checked').value === 'UMFRAGE';
|
||||
document.getElementById('homeUmfrageOptions').style.display = isUmfrage ? '' : 'none';
|
||||
document.getElementById('homeMultiChoiceRow').style.display = isUmfrage ? '' : 'none';
|
||||
if (isUmfrage && document.getElementById('homeOptionList').children.length === 0) {
|
||||
function homeToggleUmfrage(btn) {
|
||||
const options = document.getElementById('homeUmfrageOptions');
|
||||
const isShowing = options.style.display !== 'none';
|
||||
options.style.display = isShowing ? 'none' : '';
|
||||
if (btn) btn.classList.toggle('active', !isShowing);
|
||||
if (!isShowing && document.getElementById('homeOptionList').children.length === 0) {
|
||||
homeAddOption(); homeAddOption();
|
||||
}
|
||||
}
|
||||
|
||||
function homeResetUmfrage() {
|
||||
document.getElementById('homeUmfrageOptions').style.display = 'none';
|
||||
document.getElementById('homeOptionList').innerHTML = '';
|
||||
document.getElementById('homeUmfrageBtn').classList.remove('active');
|
||||
}
|
||||
|
||||
function homeAddOption() {
|
||||
const list = document.getElementById('homeOptionList');
|
||||
const idx = list.children.length;
|
||||
@@ -789,57 +742,28 @@
|
||||
list.appendChild(row);
|
||||
}
|
||||
|
||||
function homeSelectBilder(input) {
|
||||
[...input.files].forEach(f => { if (f.type.startsWith('image/')) homeProcessImage(f); });
|
||||
input.value = '';
|
||||
}
|
||||
|
||||
function homeProcessImage(file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
const maxSize = 1024;
|
||||
const canvas = document.createElement('canvas');
|
||||
const scale = Math.min(maxSize / img.width, maxSize / img.height, 1);
|
||||
canvas.width = Math.round(img.width * scale);
|
||||
canvas.height = Math.round(img.height * scale);
|
||||
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
homeComposeBilder.push(canvas.toDataURL('image/jpeg', 0.85).split(',')[1]);
|
||||
homeRenderThumbs();
|
||||
};
|
||||
img.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
function homeRenderThumbs() {
|
||||
const container = document.getElementById('homeComposeThumbs');
|
||||
container.innerHTML = '';
|
||||
homeComposeBilder.forEach((b, i) => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'compose-thumb';
|
||||
div.innerHTML = `<img src="data:image/jpeg;base64,${b}" alt="">
|
||||
<button class="compose-thumb-remove" onclick="homeRemoveThumb(${i})">✕</button>`;
|
||||
container.appendChild(div);
|
||||
renderBilderThumbs(homeComposeBilder, 'homeComposeThumbs', i => {
|
||||
homeComposeBilder.splice(i, 1);
|
||||
homeRenderThumbs();
|
||||
});
|
||||
container.style.display = homeComposeBilder.length > 0 ? 'flex' : 'none';
|
||||
}
|
||||
|
||||
function homeRemoveThumb(idx) {
|
||||
homeComposeBilder.splice(idx, 1);
|
||||
homeRenderThumbs();
|
||||
function homeSelectBilder(input) {
|
||||
[...input.files].forEach(f => processImageFile(f, homeComposeBilder, homeRenderThumbs));
|
||||
input.value = '';
|
||||
}
|
||||
|
||||
async function homeSubmitPost() {
|
||||
const text = document.getElementById('homeComposeText').value.trim();
|
||||
const hasUmfrage = document.getElementById('homeUmfrageOptions').style.display !== 'none';
|
||||
if (!text && homeComposeBilder.length === 0) return;
|
||||
const beitragTyp = document.querySelector('input[name="homeBeitragTyp"]:checked').value;
|
||||
const beitragTyp = hasUmfrage ? 'UMFRAGE' : 'TEXT';
|
||||
const multiChoice = document.getElementById('homeMultiChoice').checked;
|
||||
const isPublic = document.getElementById('homeIsPublic').checked;
|
||||
|
||||
let optionen = [];
|
||||
if (beitragTyp === 'UMFRAGE') {
|
||||
if (hasUmfrage) {
|
||||
optionen = Array.from(document.getElementById('homeOptionList').querySelectorAll('input'))
|
||||
.map(i => i.value.trim()).filter(v => v);
|
||||
if (optionen.length < 2) { alert('Mindestens 2 Optionen erforderlich.'); return; }
|
||||
@@ -856,11 +780,9 @@
|
||||
document.getElementById('homeComposeText').value = '';
|
||||
homeComposeBilder = [];
|
||||
homeRenderThumbs();
|
||||
document.querySelector('input[name="homeBeitragTyp"][value="TEXT"]').checked = true;
|
||||
homeToggleUmfrage();
|
||||
homeResetUmfrage();
|
||||
document.getElementById('homeMultiChoice').checked = false;
|
||||
document.getElementById('homeIsPublic').checked = false;
|
||||
document.getElementById('homeOptionList').innerHTML = '';
|
||||
|
||||
// Prepend in Vorschau
|
||||
const feedList = document.getElementById('feedList');
|
||||
@@ -882,7 +804,7 @@
|
||||
homeCompose.addEventListener('drop', e => {
|
||||
e.preventDefault();
|
||||
homeCompose.classList.remove('drag-over');
|
||||
[...e.dataTransfer.files].filter(f => f.type.startsWith('image/')).forEach(homeProcessImage);
|
||||
[...e.dataTransfer.files].filter(f => f.type.startsWith('image/')).forEach(f => processImageFile(f, homeComposeBilder, homeRenderThumbs));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -890,69 +812,49 @@
|
||||
|
||||
const homePostCache = {};
|
||||
|
||||
let activeLbPostId = null;
|
||||
let activeLbPostType = null;
|
||||
|
||||
function homeOpenPost(postId) {
|
||||
const p = homePostCache[postId];
|
||||
if (!p) return;
|
||||
activeLbPostId = p.postId;
|
||||
activeLbPostType = p.postType || 'FEED';
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = renderHomePostCard(p);
|
||||
const card = tempDiv.firstElementChild;
|
||||
if (card) {
|
||||
card.querySelectorAll('.post-actions').forEach(el => el.remove());
|
||||
document.getElementById('lbPostBody').innerHTML = card.innerHTML;
|
||||
_lbSetupContent(postId, 'hp', p.bilder);
|
||||
}
|
||||
loadLbComments(p.postId, activeLbPostType);
|
||||
loadLbComments(p.postId, p.postType || 'FEED');
|
||||
document.getElementById('postLightbox').classList.add('open');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeLb() {
|
||||
document.getElementById('postLightbox').classList.remove('open');
|
||||
document.body.style.overflow = '';
|
||||
activeLbPostId = null;
|
||||
activeLbPostType = null;
|
||||
}
|
||||
|
||||
document.getElementById('postLightbox').addEventListener('click', e => {
|
||||
if (e.target === document.getElementById('postLightbox')) closeLb();
|
||||
});
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.key === 'Escape' && document.getElementById('postLightbox').classList.contains('open')) closeLb();
|
||||
});
|
||||
|
||||
async function loadLbComments(postId, postType) {
|
||||
const targetType = postType === 'GROUP' ? 'GROUP_POST' : 'FEED_POST';
|
||||
try {
|
||||
const res = await fetch(`/social/kommentare?targetType=${targetType}&targetId=${postId}`);
|
||||
const comments = await res.json();
|
||||
document.getElementById('lbCommentsList').innerHTML = comments.length === 0
|
||||
? '<p style="color:var(--color-muted);font-size:0.82rem;margin:0.4rem;">Noch keine Kommentare.</p>'
|
||||
: comments.map(k => renderKommentarHtml(k, targetType, postId, { myUserId })).join('');
|
||||
} catch (_) {}
|
||||
// ── Like / Delete ──────────────────────────────────────────────────────────
|
||||
|
||||
async function likeHomePost(postId, postType) {
|
||||
const ep = postType === 'GROUP'
|
||||
? `/gruppen/${document.getElementById('hpc-'+postId)?.dataset?.gruppeId}/posts/${postId}/like`
|
||||
: `/feed/posts/${postId}/like`;
|
||||
await fetch(ep, { method: 'POST' });
|
||||
const btn = document.getElementById('hlk-' + postId);
|
||||
const lc = document.getElementById('hlkc-' + postId);
|
||||
const was = btn.classList.contains('active');
|
||||
btn.classList.toggle('active', !was);
|
||||
lc.textContent = parseInt(lc.textContent) + (was ? -1 : 1);
|
||||
}
|
||||
|
||||
async function postLbComment() {
|
||||
if (!activeLbPostId) return;
|
||||
const input = document.getElementById('lbCommentInput');
|
||||
const text = input.value.trim();
|
||||
if (!text) return;
|
||||
const targetType = activeLbPostType === 'GROUP' ? 'GROUP_POST' : 'FEED_POST';
|
||||
await fetch('/social/kommentare', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ targetType, targetId: activeLbPostId, text })
|
||||
});
|
||||
input.value = '';
|
||||
await loadLbComments(activeLbPostId, activeLbPostType);
|
||||
async function deleteHomePost(postId) {
|
||||
if (!confirm('Post löschen?')) return;
|
||||
const res = await fetch('/feed/posts/' + postId, { method: 'DELETE' });
|
||||
if (res.ok) document.getElementById('hpc-' + postId)?.remove();
|
||||
}
|
||||
|
||||
async function deleteKommentar(kommentarId, targetType, targetId) {
|
||||
await fetch('/social/kommentare/' + kommentarId, { method: 'DELETE' });
|
||||
await loadLbComments(targetId, activeLbPostType);
|
||||
}
|
||||
// ── Post-Karte ────────────────────────────────────────────────────────────
|
||||
|
||||
const homeEditBilder = new Map();
|
||||
|
||||
function renderHomePostCard(p) {
|
||||
homePostCache[p.postId] = p;
|
||||
@@ -963,7 +865,8 @@
|
||||
const groupBadge = p.postType === 'GROUP' && p.gruppeId
|
||||
? `<span class="gruppe-badge">👥 ${esc(p.gruppeName)}</span>`
|
||||
: '';
|
||||
const bildHtml = bilderCarousel(p.bilder);
|
||||
const bildHtml = bilderGrid(p.bilder);
|
||||
const editedLabel = p.editedAt ? ` <span style="font-size:0.75rem;color:var(--color-muted);">(bearbeitet)</span>` : '';
|
||||
let umfrageHtml = '';
|
||||
if (p.beitragTyp === 'UMFRAGE' && p.optionen && p.optionen.length > 0) {
|
||||
const totalVotes = p.optionen.reduce((s, o) => s + o.stimmenCount, 0);
|
||||
@@ -976,24 +879,74 @@
|
||||
</div>`;
|
||||
}).join('') + `<div class="umfrage-total">${totalVotes} Stimme${totalVotes !== 1 ? 'n' : ''}</div></div>`;
|
||||
}
|
||||
return `<div class="post-card" onclick="homeOpenPost('${p.postId}')" style="cursor:pointer">
|
||||
const canOwn = p.postType === 'FEED' && p.authorId === myUserId;
|
||||
const ownBtns = canOwn
|
||||
? `<div style="margin-left:auto;display:flex;gap:0.4rem;">
|
||||
<button class="post-action-btn" onclick="event.stopPropagation();startHomeEdit('${p.postId}')" title="Bearbeiten" style="color:var(--color-muted)">✏</button>
|
||||
<button class="post-action-btn post-delete" onclick="event.stopPropagation();deleteHomePost('${p.postId}')" title="Löschen">🗑</button>
|
||||
</div>`
|
||||
: '';
|
||||
const gruppeIdAttr = p.gruppeId ? ` data-gruppe-id="${p.gruppeId}"` : '';
|
||||
return `<div class="post-card" id="hpc-${p.postId}"${gruppeIdAttr} onclick="homeOpenPost('${p.postId}')">
|
||||
<div class="post-header">
|
||||
<div class="post-avatar">${avatarHtml}</div>
|
||||
<div>
|
||||
<div class="post-author">${esc(p.authorName)}${privacyLabel}</div>
|
||||
<div class="post-meta">${fmtDate(p.createdAt)}${groupBadge}</div>
|
||||
<div class="post-meta" id="hpm-${p.postId}">${fmtDate(p.createdAt)}${editedLabel}${groupBadge}</div>
|
||||
</div>
|
||||
${ownBtns}
|
||||
</div>
|
||||
<div class="post-text">${renderTextWithHashtags(p.text || '')}</div>
|
||||
${bildHtml}
|
||||
${umfrageHtml}
|
||||
<div id="hpva-${p.postId}">
|
||||
<div class="post-text">${renderTextWithHashtags(p.text || '')}</div>
|
||||
<div id="hpbi-${p.postId}">${bildHtml}</div>
|
||||
</div>
|
||||
<div id="hpea-${p.postId}" style="display:none;"></div>
|
||||
<div id="hpum-${p.postId}">${umfrageHtml}</div>
|
||||
<div class="post-actions">
|
||||
<button class="post-action-btn${p.likedByMe ? ' active' : ''}">♥ <span>${p.likeCount}</span></button>
|
||||
<button class="post-action-btn">💬 <span>${p.kommentarCount}</span></button>
|
||||
<button class="post-action-btn${p.likedByMe ? ' active' : ''}" id="hlk-${p.postId}" onclick="event.stopPropagation();likeHomePost('${p.postId}','${p.postType}')">♥ <span id="hlkc-${p.postId}">${p.likeCount}</span></button>
|
||||
<button class="post-action-btn" onclick="event.stopPropagation();homeOpenPost('${p.postId}')">💬 <span id="hkc-${p.postId}">${p.kommentarCount}</span></button>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// ── Post-Bearbeitung (Home) ───────────────────────────────────────────────
|
||||
|
||||
function startHomeEdit(postId) {
|
||||
const data = homePostCache[postId];
|
||||
if (!data) return;
|
||||
startPostEdit({ postId, prefix: 'hp', data, editBilderMap: homeEditBilder,
|
||||
saveFn: 'saveHomeEdit', cancelFn: 'cancelHomeEdit',
|
||||
addImgFn: 'homeEditAddImg', addOptionFn: 'homeEditAddOption', rmImgFn: 'homeEditRmImg' });
|
||||
}
|
||||
function cancelHomeEdit(postId) { cancelPostEdit(postId, 'hp', homeEditBilder); }
|
||||
function homeEditRmImg(postId, idx) {
|
||||
homeEditBilder.get(postId).splice(idx, 1);
|
||||
_renderEditThumbs(homeEditBilder, postId, 'hp', 'homeEditRmImg');
|
||||
}
|
||||
function homeEditAddImg(input, postId) {
|
||||
[...input.files].forEach(f => processImageFile(f, homeEditBilder.get(postId), () => _renderEditThumbs(homeEditBilder, postId, 'hp', 'homeEditRmImg')));
|
||||
input.value = '';
|
||||
}
|
||||
function homeEditAddOption(postId) { editAddOptionRow(`hpeo-${postId}`); }
|
||||
async function saveHomeEdit(postId) {
|
||||
const cached = homePostCache[postId];
|
||||
await savePostEdit({ postId, prefix: 'hp', endpoint: `/feed/posts/${postId}`,
|
||||
isUmfrage: cached?.beitragTyp === 'UMFRAGE', editBilderMap: homeEditBilder,
|
||||
onSuccess: updated => {
|
||||
homePostCache[postId] = { ...cached, text: updated.text, bilder: updated.bilder || [], optionen: updated.optionen || [], multiChoice: updated.multiChoice };
|
||||
const totalVotes = (updated.optionen || []).reduce((s, o) => s + o.stimmenCount, 0);
|
||||
const umfrageHtml = updated.optionen?.length > 0
|
||||
? '<div style="margin-top:0.5rem;">' + updated.optionen.map(o => {
|
||||
const pct = totalVotes > 0 ? Math.round(o.stimmenCount / totalVotes * 100) : 0;
|
||||
return `<div class="umfrage-option-bar"><div class="umfrage-bar-fill" style="width:${pct}%"></div>
|
||||
<div class="umfrage-bar-content"><span>${esc(o.text)}</span><span>${pct}%</span></div></div>`;
|
||||
}).join('') + `<div class="umfrage-total">${totalVotes} Stimme${totalVotes !== 1 ? 'n' : ''}</div></div>`
|
||||
: '';
|
||||
applyPostEditDom(postId, 'hp', updated, umfrageHtml);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function loadFeed() {
|
||||
try {
|
||||
const res = await fetch('/feed/mine?size=3&page=0');
|
||||
|
||||
Reference in New Issue
Block a user