Auto-Commit: 2026-06-21 14:51:15
This commit is contained in:
@@ -14,6 +14,54 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
// --- Tablet Mockup Interactive Demo ---
|
||||
const captureBtn = document.getElementById('demo-capture-btn');
|
||||
const screenWelcome = document.getElementById('demo-screen-welcome');
|
||||
const screenCountdown = document.getElementById('demo-screen-countdown');
|
||||
const screenPreview = document.getElementById('demo-screen-preview');
|
||||
const timerDisplay = document.getElementById('demo-timer');
|
||||
const flashOverlay = document.getElementById('demo-flash');
|
||||
|
||||
const btnPrint = document.getElementById('demo-btn-print');
|
||||
const btnReset = document.getElementById('demo-btn-reset');
|
||||
|
||||
if (captureBtn && screenWelcome && screenCountdown && screenPreview && timerDisplay && flashOverlay) {
|
||||
captureBtn.addEventListener('click', () => {
|
||||
// Step 1: Switch screen to countdown
|
||||
screenWelcome.style.display = 'none';
|
||||
screenCountdown.style.display = 'flex';
|
||||
|
||||
// Step 2: 3-second countdown countdown
|
||||
let timeLeft = 3;
|
||||
timerDisplay.textContent = timeLeft;
|
||||
|
||||
const timerInterval = setInterval(() => {
|
||||
timeLeft--;
|
||||
if (timeLeft > 0) {
|
||||
timerDisplay.textContent = timeLeft;
|
||||
} else {
|
||||
clearInterval(timerInterval);
|
||||
// Step 3: Trigger Camera Flash overlay
|
||||
flashOverlay.classList.add('flash-active');
|
||||
|
||||
setTimeout(() => {
|
||||
flashOverlay.classList.remove('flash-active');
|
||||
// Step 4: Transition to captured photo preview screen
|
||||
screenCountdown.style.display = 'none';
|
||||
screenPreview.style.display = 'flex';
|
||||
}, 400);
|
||||
}
|
||||
}, 800);
|
||||
});
|
||||
}
|
||||
|
||||
if (btnReset && screenWelcome && screenPreview) {
|
||||
btnReset.addEventListener('click', () => {
|
||||
screenPreview.style.display = 'none';
|
||||
screenWelcome.style.display = 'flex';
|
||||
});
|
||||
}
|
||||
|
||||
// --- Accordion FAQ ---
|
||||
const accordionHeaders = document.querySelectorAll('.accordion-header');
|
||||
|
||||
@@ -91,6 +139,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
localStorage.setItem('schnappix_upvoted_ids', JSON.stringify(upvotedIds));
|
||||
};
|
||||
|
||||
// Admin State
|
||||
let isAdmin = sessionStorage.getItem('schnappix_is_admin') === 'true';
|
||||
|
||||
const renderFeedback = (filter = 'all') => {
|
||||
if (!feedbackList) return;
|
||||
feedbackList.innerHTML = '';
|
||||
@@ -115,11 +166,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
categoryLabel = 'Lob';
|
||||
}
|
||||
|
||||
// Show delete button if user is admin
|
||||
const deleteBtnHtml = isAdmin
|
||||
? `<button class="fb-admin-delete-btn" data-id="${item.id}" title="Eintrag löschen"><i class="fa-solid fa-trash"></i> Löschen</button>`
|
||||
: '';
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="fb-card-content">
|
||||
<div class="fb-meta">
|
||||
<span class="fb-tag ${item.type}">${badgeIcon} ${categoryLabel}</span>
|
||||
<span class="fb-author">von ${escapeHtml(item.author)}</span>
|
||||
${deleteBtnHtml}
|
||||
</div>
|
||||
<h4>${escapeHtml(item.title)}</h4>
|
||||
<p>${escapeHtml(item.text)}</p>
|
||||
@@ -136,6 +193,22 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
|
||||
setupUpvoteButtons();
|
||||
setupAdminDeleteButtons();
|
||||
};
|
||||
|
||||
const setupAdminDeleteButtons = () => {
|
||||
if (!isAdmin) return;
|
||||
const deleteButtons = document.querySelectorAll('.fb-admin-delete-btn');
|
||||
deleteButtons.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const id = btn.getAttribute('data-id');
|
||||
if (confirm('Möchten Sie diesen Eintrag wirklich permanent löschen?')) {
|
||||
feedbackData = feedbackData.filter(item => item.id !== id);
|
||||
saveToLocalStorage();
|
||||
renderFeedback(getActiveFilter());
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const escapeHtml = (str) => {
|
||||
@@ -224,25 +297,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const modals = document.querySelectorAll('.modal-overlay');
|
||||
const closeButtons = document.querySelectorAll('.modal-close');
|
||||
|
||||
modalTriggers.forEach(trigger => {
|
||||
trigger.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
const targetId = trigger.getAttribute('href').substring(1);
|
||||
const targetModal = document.getElementById(targetId);
|
||||
if (targetModal) {
|
||||
targetModal.classList.add('open');
|
||||
document.body.style.overflow = 'hidden'; // Stop scrolling background
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// --- Modal close helpers for admin modals ---
|
||||
const closeModal = (modal) => {
|
||||
modal.classList.remove('open');
|
||||
// Only restore scroll if no other modals are open
|
||||
const anyOpen = Array.from(modals).some(m => m.classList.contains('open'));
|
||||
if (!anyOpen) {
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
document.body.style.overflow = '';
|
||||
};
|
||||
|
||||
closeButtons.forEach(btn => {
|
||||
@@ -253,7 +311,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
|
||||
modals.forEach(modal => {
|
||||
// Close modal when clicking outside of the content block
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) {
|
||||
closeModal(modal);
|
||||
@@ -261,7 +318,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// Close modal on Escape key press
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
modals.forEach(modal => {
|
||||
@@ -270,6 +326,100 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
|
||||
// --- Admin Panel Modals & Operations ---
|
||||
const adminTrigger = document.getElementById('admin-login-trigger');
|
||||
const adminLoginModal = document.getElementById('admin-login-modal');
|
||||
const adminPanelModal = document.getElementById('admin-panel-modal');
|
||||
const adminLoginForm = document.getElementById('admin-login-form');
|
||||
const adminPasswordInput = document.getElementById('admin-password');
|
||||
const adminLoginError = document.getElementById('admin-login-error');
|
||||
|
||||
const adminLogoutBtn = document.getElementById('admin-logout-btn');
|
||||
const adminExportBtn = document.getElementById('admin-export-btn');
|
||||
const exportContainer = document.getElementById('export-container');
|
||||
const exportTextarea = document.getElementById('export-textarea');
|
||||
|
||||
if (adminTrigger) {
|
||||
adminTrigger.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
if (isAdmin) {
|
||||
adminPanelModal.classList.add('open');
|
||||
} else {
|
||||
adminLoginModal.classList.add('open');
|
||||
adminPasswordInput.focus();
|
||||
}
|
||||
document.body.style.overflow = 'hidden';
|
||||
});
|
||||
}
|
||||
|
||||
if (adminLoginForm) {
|
||||
adminLoginForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const password = adminPasswordInput.value;
|
||||
// Admin password matching the default app settings: "1234"
|
||||
if (password === '1234') {
|
||||
isAdmin = true;
|
||||
sessionStorage.setItem('schnappix_is_admin', 'true');
|
||||
adminPasswordInput.value = '';
|
||||
adminLoginError.style.display = 'none';
|
||||
|
||||
// Switch Modals
|
||||
adminLoginModal.classList.remove('open');
|
||||
adminPanelModal.classList.add('open');
|
||||
|
||||
// Re-render to show trash cans
|
||||
renderFeedback(getActiveFilter());
|
||||
} else {
|
||||
adminLoginError.style.display = 'block';
|
||||
adminPasswordInput.value = '';
|
||||
adminPasswordInput.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (adminLogoutBtn) {
|
||||
adminLogoutBtn.addEventListener('click', () => {
|
||||
isAdmin = false;
|
||||
sessionStorage.removeItem('schnappix_is_admin');
|
||||
adminPanelModal.classList.remove('open');
|
||||
document.body.style.overflow = '';
|
||||
|
||||
// Hide export code if visible
|
||||
if (exportContainer) exportContainer.style.display = 'none';
|
||||
|
||||
// Re-render to hide trash cans
|
||||
renderFeedback(getActiveFilter());
|
||||
});
|
||||
}
|
||||
|
||||
if (adminExportBtn && exportContainer && exportTextarea) {
|
||||
adminExportBtn.addEventListener('click', () => {
|
||||
// Strip out own custom elements or internal helper flags if necessary
|
||||
const cleanFeedback = feedbackData.map(item => ({
|
||||
id: item.id,
|
||||
author: item.author,
|
||||
type: item.type,
|
||||
title: item.title,
|
||||
text: item.text,
|
||||
upvotes: item.upvotes,
|
||||
voted: false
|
||||
}));
|
||||
|
||||
exportTextarea.value = JSON.stringify(cleanFeedback, null, 4);
|
||||
exportContainer.style.display = 'block';
|
||||
exportTextarea.select();
|
||||
});
|
||||
}
|
||||
|
||||
// Modal Close overrides to reset error states
|
||||
const allCloseButtons = document.querySelectorAll('.modal-close');
|
||||
allCloseButtons.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
if (adminLoginError) adminLoginError.style.display = 'none';
|
||||
if (exportContainer) exportContainer.style.display = 'none';
|
||||
});
|
||||
});
|
||||
|
||||
// Initial render
|
||||
renderFeedback();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user