Files

418 lines
17 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<link rel="icon" type="image/png" href="favicon.png">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Schnappix - Hintergrund Upload</title>
<meta name="description" content="Lade deine eigenen, maßgeschneiderten Rahmen für Schnappix hoch.">
<link rel="stylesheet" href="style.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Outfit:wght@500;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.upload-section {
padding: 140px 0 100px;
min-height: 100vh;
display: flex;
align-items: center;
}
.upload-card {
max-width: 600px;
margin: 0 auto;
padding: 40px;
text-align: center;
}
.upload-area {
border: 2px dashed var(--border-color);
border-radius: 16px;
padding: 40px 20px;
margin: 30px 0;
background: rgba(5, 5, 16, 0.4);
cursor: pointer;
transition: var(--transition-smooth);
position: relative;
}
.upload-area:hover, .upload-area.dragover {
border-color: var(--primary-color);
background: rgba(255, 43, 214, 0.05);
box-shadow: 0 0 20px rgba(255, 43, 214, 0.1);
}
.upload-icon {
font-size: 48px;
color: var(--accent-color);
margin-bottom: 16px;
transition: var(--transition-smooth);
}
.upload-area:hover .upload-icon {
transform: translateY(-5px);
color: var(--primary-color);
}
.upload-text {
font-size: 16px;
color: #fff;
font-weight: 500;
margin-bottom: 8px;
}
.upload-hint {
font-size: 13px;
color: var(--text-muted);
}
#file-input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
.validation-messages {
margin-top: 20px;
text-align: left;
display: none;
background: rgba(5, 5, 16, 0.8);
padding: 15px;
border-radius: 8px;
border-left: 3px solid var(--accent-color);
}
.validation-messages p {
margin-bottom: 8px;
font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
}
.validation-messages p:last-child {
margin-bottom: 0;
}
.valid-msg { color: #4ade80; }
.invalid-msg { color: #ff4466; }
.preview-container {
display: none;
margin-top: 20px;
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--border-color);
background: #000;
position: relative;
}
.preview-container img {
width: 100%;
height: auto;
display: block;
}
.preview-overlay-checkerboard {
background-image: linear-gradient(45deg, #222 25%, transparent 25%),
linear-gradient(-45deg, #222 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #222 75%),
linear-gradient(-45deg, transparent 75%, #222 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
}
#submit-btn {
margin-top: 25px;
display: none;
}
.email-info {
font-size: 12px;
color: var(--text-muted);
margin-top: 15px;
display: none;
}
</style>
</head>
<body>
<!-- Header Navigation -->
<header class="main-header">
<div class="container nav-container">
<div class="logo">
<a href="index.html" style="text-decoration: none;"><span class="logo-glow">Schnappix</span></a>
</div>
<nav class="nav-links">
<a href="features.html">Features</a>
<a href="upload.html" class="active-nav">Upload</a>
<a href="faq.html">FAQ</a>
<a href="feedback.html">Feedback Hub</a>
<a href="tester.html">App Testing</a>
<a href="#" id="admin-login-trigger"><i class="fa-solid fa-user-gear"></i> Admin</a>
</nav>
<button class="menu-toggle" aria-label="Menu öffnen">
<i class="fa-solid fa-bars"></i>
</button>
</div>
</header>
<!-- Upload Section -->
<section class="upload-section">
<div class="container">
<div class="upload-card glass">
<h1 style="font-family: var(--font-titles); font-size: 32px; margin-bottom: 10px;">Hintergrund <span class="text-gradient">Upload</span></h1>
<p style="color: var(--text-muted); font-size: 15px;">Lade dein eigenes PNG hoch. Nach erfolgreicher Prüfung wird dein Rahmen in die App eingebaut und ist dort für alle Nutzer sichtbar.</p>
<!-- FormSubmit.co is used to send the email directly with attachment without a backend -->
<form id="bg-upload-form">
<div class="upload-area" id="drop-zone">
<i class="fa-solid fa-cloud-arrow-up upload-icon"></i>
<div class="upload-text">Datei hier ablegen oder klicken</div>
<div class="upload-hint">Erforderlich: PNG Format • Exakt 1500x1000 Pixel</div>
<input type="file" id="file-input" name="background_image" accept="image/png" required>
</div>
<div class="form-group" style="text-align: left; display: none;" id="frame-info">
<label for="frame-name">Name des Rahmens (nur Kleinbuchstaben & Zahlen)</label>
<input type="text" id="frame-name" name="frame_name" pattern="[a-z0-9_]+" placeholder="z.B. summer1" required>
<div class="upload-hint" style="margin-top: 5px;">Wird gespeichert als: <strong style="color: var(--primary-color);">frame_<span id="frame-preview-name">...</span>.png</strong></div>
</div>
<div class="form-group" style="text-align: left; display: none;" id="customer-info">
<label for="customer-email">Deine E-Mail Adresse (für Rückfragen)</label>
<input type="email" id="customer-email" name="email" placeholder="mail@example.com" required>
</div>
<div class="validation-messages" id="validation-box">
<p id="val-format"><i class="fa-solid fa-circle-notch fa-spin"></i> Überprüfe Dateiformat (.png)...</p>
<p id="val-resolution"><i class="fa-solid fa-circle-notch fa-spin"></i> Überprüfe Auflösung (1500x1000)...</p>
</div>
<div class="preview-container" id="preview-box">
<div class="preview-overlay-checkerboard"></div>
<img id="image-preview" src="" alt="Vorschau">
</div>
<button type="submit" class="btn btn-primary btn-block" id="submit-btn">
<i class="fa-solid fa-paper-plane" style="margin-right: 8px;"></i> Hintergrund absenden
</button>
</form>
</div>
</div>
</section>
<!-- Footer -->
<footer class="main-footer">
<div class="container footer-container">
<p>&copy; 2026 Schnappix. Alle Rechte vorbehalten.</p>
<div class="footer-links">
<a href="impressum.html">Impressum</a>
<a href="datenschutz.html">Datenschutzerklärung</a>
</div>
</div>
</footer>
<!-- Admin Modals (Required for Header Nav) -->
<div id="admin-login-modal" class="modal-overlay">
<div class="modal-content glass">
<button class="modal-close" aria-label="Schließen">&times;</button>
<h2>Admin Login</h2>
<form id="admin-login-form">
<div class="form-group">
<label for="admin-password">Admin Passwort</label>
<input type="password" id="admin-password" placeholder="Passwort eingeben" required>
</div>
<div id="admin-login-error" style="color: #ff4466; font-size: 14px; margin-bottom: 15px; display: none;">Falsches Passwort!</div>
<button type="submit" class="btn btn-primary btn-block">Anmelden</button>
</form>
</div>
</div>
<script src="app.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const dropZone = document.getElementById('drop-zone');
const fileInput = document.getElementById('file-input');
const validationBox = document.getElementById('validation-box');
const valFormat = document.getElementById('val-format');
const valResolution = document.getElementById('val-resolution');
const previewBox = document.getElementById('preview-box');
const imagePreview = document.getElementById('image-preview');
const submitBtn = document.getElementById('submit-btn');
const frameInfo = document.getElementById('frame-info');
const frameNameInput = document.getElementById('frame-name');
const framePreviewName = document.getElementById('frame-preview-name');
const customerInfo = document.getElementById('customer-info');
frameNameInput.addEventListener('input', (e) => {
const val = e.target.value.trim().toLowerCase().replace(/[^a-z0-9_]/g, '');
e.target.value = val;
framePreviewName.textContent = val || '...';
});
// Drag and Drop Effects
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, () => dropZone.classList.add('dragover'), false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, () => dropZone.classList.remove('dragover'), false);
});
dropZone.addEventListener('drop', (e) => {
const dt = e.dataTransfer;
const files = dt.files;
if(files.length > 0) {
fileInput.files = files;
handleFile(files[0]);
}
});
fileInput.addEventListener('change', function() {
if(this.files && this.files.length > 0) {
handleFile(this.files[0]);
}
});
function setValidationMsg(el, isValid, validText, invalidText) {
if (isValid) {
el.innerHTML = `<i class="fa-solid fa-check valid-msg"></i> ${validText}`;
el.className = 'valid-msg';
} else {
el.innerHTML = `<i class="fa-solid fa-xmark invalid-msg"></i> ${invalidText}`;
el.className = 'invalid-msg';
}
}
function handleFile(file) {
// Reset UI
validationBox.style.display = 'block';
previewBox.style.display = 'none';
submitBtn.style.display = 'none';
frameInfo.style.display = 'none';
customerInfo.style.display = 'none';
valFormat.innerHTML = `<i class="fa-solid fa-circle-notch fa-spin"></i> Überprüfe Dateiformat...`;
valFormat.className = '';
valResolution.innerHTML = `<i class="fa-solid fa-circle-notch fa-spin"></i> Überprüfe Auflösung...`;
valResolution.className = '';
// 1. Check Format
const isPng = file.type === 'image/png';
if (!isPng) {
setValidationMsg(valFormat, false, '', 'Fehler: Die Datei muss im .png Format sein.');
setValidationMsg(valResolution, false, '', 'Abbruch: Falsches Format.');
return;
} else {
setValidationMsg(valFormat, true, 'Format ist korrekt (.png)', '');
}
// 2. Check Resolution
const reader = new FileReader();
reader.onload = function(e) {
const img = new Image();
img.onload = function() {
const width = this.width;
const height = this.height;
if (width === 1500 && height === 1000) {
setValidationMsg(valResolution, true, `Auflösung ist korrekt (${width}x${height}px)`, '');
// Show Preview and Submit Button
imagePreview.src = e.target.result;
previewBox.style.display = 'block';
frameInfo.style.display = 'block';
customerInfo.style.display = 'block';
submitBtn.style.display = 'block';
} else {
setValidationMsg(valResolution, false, '', `Fehler: Falsche Auflösung (${width}x${height}px). Erwartet: 1500x1000px.`);
}
};
img.onerror = function() {
setValidationMsg(valResolution, false, '', 'Fehler: Bilddatei konnte nicht gelesen werden.');
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
}
const form = document.getElementById('bg-upload-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const originalBtnText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fa-solid fa-circle-notch fa-spin"></i> Lade hoch...';
submitBtn.disabled = true;
try {
const response = await fetch('upload_backend.php', {
method: 'POST',
body: formData
});
const responseText = await response.text();
let result;
try {
result = JSON.parse(responseText);
} catch (e) {
console.error('Server antwortete nicht mit gültigem JSON:', responseText);
alert('Ein Server-Fehler ist aufgetreten (siehe Konsole). Das Bild wurde eventuell trotzdem hochgeladen.');
form.reset();
framePreviewName.textContent = '...';
previewBox.style.display = 'none';
submitBtn.style.display = 'none';
frameInfo.style.display = 'none';
customerInfo.style.display = 'none';
validationBox.style.display = 'none';
return;
}
if (response.ok) {
alert('Erfolgreich hochgeladen!');
form.reset();
framePreviewName.textContent = '...';
previewBox.style.display = 'none';
submitBtn.style.display = 'none';
frameInfo.style.display = 'none';
customerInfo.style.display = 'none';
validationBox.style.display = 'none';
} else {
alert('Fehler: ' + (result.error || 'Unbekannter Fehler'));
}
} catch (error) {
console.error('Upload Error:', error);
alert('Upload fehlgeschlagen. Bitte prüfe deine Verbindung.');
} finally {
submitBtn.innerHTML = originalBtnText;
submitBtn.disabled = false;
}
});
});
</script>
</body>
</html>