Feature: Foto-Upload für Mitglieder im Admin-Panel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
84
admin.html
84
admin.html
@@ -214,6 +214,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Member Photo Modal -->
|
||||||
|
<div class="modal-overlay" id="modal-member-photo">
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<div class="modal-title" id="member-photo-modal-title">Foto bearbeiten</div>
|
||||||
|
<button class="modal-close" onclick="closeAdminModal('modal-member-photo')">✕</button>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="member-photo-name">
|
||||||
|
<div style="display:flex;align-items:center;gap:16px;margin:16px 0;">
|
||||||
|
<img id="member-photo-thumb" class="photo-thumb" style="width:80px;height:80px;display:none;" src="" alt="">
|
||||||
|
<div id="member-photo-initials" style="width:80px;height:80px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:white;font-size:1.4rem;font-weight:700;flex-shrink:0;"></div>
|
||||||
|
<div class="photo-actions" style="flex-direction:column;align-items:flex-start;">
|
||||||
|
<label class="btn-file-label">📁 Foto wählen<input type="file" id="member-photo-file" accept="image/*" style="display:none" onchange="handleMemberPhotoFile(this)"></label>
|
||||||
|
<button class="btn btn-danger btn-sm" id="member-photo-remove" onclick="removeMemberPhoto()" style="display:none;margin-top:6px;">✕ Foto entfernen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-ghost" onclick="closeAdminModal('modal-member-photo')">Abbrechen</button>
|
||||||
|
<button class="btn btn-primary" onclick="saveMemberPhoto()">Speichern</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Import from Chapter Modal -->
|
<!-- Import from Chapter Modal -->
|
||||||
<div class="modal-overlay" id="modal-import-chapter">
|
<div class="modal-overlay" id="modal-import-chapter">
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
@@ -569,16 +592,75 @@ function renderMembersList() {
|
|||||||
const photoB64 = ex.photoB64 || ex.offlinePhotoB64 || null;
|
const photoB64 = ex.photoB64 || ex.offlinePhotoB64 || null;
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = 'member-item';
|
div.className = 'member-item';
|
||||||
|
div.style.cursor = 'pointer';
|
||||||
|
div.title = 'Foto bearbeiten';
|
||||||
div.innerHTML = `${avatarHtml(m.name, photoB64, m.photoUrl, 40)}
|
div.innerHTML = `${avatarHtml(m.name, photoB64, m.photoUrl, 40)}
|
||||||
<div style="flex:1;min-width:0;">
|
<div style="flex:1;min-width:0;">
|
||||||
<div style="font-weight:600;font-size:0.88rem;">${escHtml(m.name)}</div>
|
<div style="font-weight:600;font-size:0.88rem;">${escHtml(m.name)}</div>
|
||||||
<div style="font-size:0.75rem;color:var(--muted);">${escHtml(m.company||'')}${m.specialty?' · '+escHtml(m.specialty):''}</div>
|
<div style="font-size:0.75rem;color:var(--muted);">${escHtml(m.company||'')}${m.specialty?' · '+escHtml(m.specialty):''}</div>
|
||||||
</div>
|
</div>
|
||||||
<span style="font-size:0.72rem;color:${photoB64?'var(--success)':'var(--muted)'};">${photoB64?'✓ Foto':'kein Foto'}</span>`;
|
<span style="font-size:0.72rem;color:${photoB64?'var(--success)':'#d97706'};">${photoB64?'✓ Foto':'+ Foto'}</span>`;
|
||||||
|
div.onclick = () => openMemberPhotoModal(m.name, photoB64);
|
||||||
container.appendChild(div);
|
container.appendChild(div);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _memberPhotoB64 = null;
|
||||||
|
|
||||||
|
function openMemberPhotoModal(name, currentPhotoB64) {
|
||||||
|
_memberPhotoB64 = currentPhotoB64 || null;
|
||||||
|
document.getElementById('member-photo-name').value = name;
|
||||||
|
document.getElementById('member-photo-modal-title').textContent = name;
|
||||||
|
updateMemberPhotoUI(_memberPhotoB64, name);
|
||||||
|
openAdminModal('modal-member-photo');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMemberPhotoUI(b64, name) {
|
||||||
|
_memberPhotoB64 = b64;
|
||||||
|
const thumb = document.getElementById('member-photo-thumb');
|
||||||
|
const initials = document.getElementById('member-photo-initials');
|
||||||
|
const removeBtn = document.getElementById('member-photo-remove');
|
||||||
|
if (b64) {
|
||||||
|
thumb.src = b64; thumb.style.display = 'block';
|
||||||
|
initials.style.display = 'none';
|
||||||
|
removeBtn.style.display = 'inline-flex';
|
||||||
|
} else {
|
||||||
|
thumb.src = ''; thumb.style.display = 'none';
|
||||||
|
initials.style.display = 'flex';
|
||||||
|
initials.style.background = getColor(name || '');
|
||||||
|
initials.textContent = getInitials(name || '');
|
||||||
|
removeBtn.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMemberPhotoFile(input) {
|
||||||
|
const file = input.files && input.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
const name = document.getElementById('member-photo-name').value;
|
||||||
|
resizePhotoToBase64(file).then(b64 => updateMemberPhotoUI(b64, name)).catch(e => alert(e.message));
|
||||||
|
input.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeMemberPhoto() {
|
||||||
|
updateMemberPhotoUI(null, document.getElementById('member-photo-name').value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveMemberPhoto() {
|
||||||
|
const name = document.getElementById('member-photo-name').value;
|
||||||
|
const extras = loadExtras();
|
||||||
|
const key = extrasKey(name);
|
||||||
|
if (!extras[key]) extras[key] = {};
|
||||||
|
if (_memberPhotoB64) {
|
||||||
|
extras[key].photoB64 = _memberPhotoB64;
|
||||||
|
} else {
|
||||||
|
delete extras[key].photoB64;
|
||||||
|
delete extras[key].offlinePhotoB64;
|
||||||
|
}
|
||||||
|
saveExtras(extras);
|
||||||
|
closeAdminModal('modal-member-photo');
|
||||||
|
renderMembersList();
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchMembersAdmin() {
|
async function fetchMembersAdmin() {
|
||||||
const statusEl = document.getElementById('members-status');
|
const statusEl = document.getElementById('members-status');
|
||||||
statusEl.textContent = 'Lade vom Server…'; statusEl.style.color = 'var(--muted)';
|
statusEl.textContent = 'Lade vom Server…'; statusEl.style.color = 'var(--muted)';
|
||||||
|
|||||||
Reference in New Issue
Block a user