Capture-Buttons: 📸 Foto 🎬 Video 🎤 Audio direkt aufnehmen

- Drei große Touch-Buttons (min 64px, flex-row) statt einem Dateifeld
- capture='environment' für Foto/Video → Kamera-App öffnet direkt
- capture (ohne Wert) für Audio → Sprachrekorder öffnet direkt
- 'Choose File' als Galerie-Fallback für bestehende Dateien
- Overlay max-height erhöht (85vh Desktop, 90vh Mobile)
  damit alle Buttons ohne Scrollen sichtbar sind
- JavaScript prüft alle 4 Inputs auf Dateien
This commit is contained in:
Hermes Agent
2026-06-17 15:40:17 +02:00
parent fa4204112b
commit 03496ab2ff
+32 -7
View File
@@ -1870,7 +1870,7 @@ def public_frontend():
.submit-bubble { bottom:1rem; right:5rem; } .submit-bubble { bottom:1rem; right:5rem; }
.chat-overlay { bottom:5rem; right:0.5rem; width:calc(100vw - 1rem); max-height:60vh; } .chat-overlay { bottom:5rem; right:0.5rem; width:calc(100vw - 1rem); max-height:60vh; }
.chat-bubble { bottom:1rem; right:1rem; } .chat-bubble { bottom:1rem; right:1rem; }
.submit-overlay { bottom:5rem; right:0.5rem; width:calc(100vw - 1rem); max-height:65vh; } .submit-overlay { bottom:4rem; right:0.5rem; width:calc(100vw - 1rem); max-height:90vh; }
} }
.chat-bubble { position:fixed; bottom:1.5rem; right:1.5rem; z-index:9999; .chat-bubble { position:fixed; bottom:1.5rem; right:1.5rem; z-index:9999;
width:56px; height:56px; border-radius:50%; background:#20228a; width:56px; height:56px; border-radius:50%; background:#20228a;
@@ -1923,7 +1923,7 @@ def public_frontend():
.submit-bubble:active { transform:scale(0.95); } .submit-bubble:active { transform:scale(0.95); }
.submit-overlay { position:fixed; bottom:5.5rem; right:1.5rem; z-index:9998; .submit-overlay { position:fixed; bottom:5.5rem; right:1.5rem; z-index:9998;
width:400px; max-width:calc(100vw - 2rem); max-height:70vh; width:400px; max-width:calc(100vw - 2rem); max-height:85vh;
background:#fff; border-radius:18px; box-shadow:0 12px 48px rgba(0,0,0,0.22); background:#fff; border-radius:18px; box-shadow:0 12px 48px rgba(0,0,0,0.22);
display:none; flex-direction:column; overflow:hidden; } display:none; flex-direction:column; overflow:hidden; }
.submit-overlay.open { display:flex; } .submit-overlay.open { display:flex; }
@@ -1932,7 +1932,7 @@ def public_frontend():
.submit-header button { background:none; border:none; color:#fff; font-size:1.3rem; .submit-header button { background:none; border:none; color:#fff; font-size:1.3rem;
cursor:pointer; opacity:0.8; padding:0; line-height:1; } cursor:pointer; opacity:0.8; padding:0; line-height:1; }
.submit-header button:hover { opacity:1; } .submit-header button:hover { opacity:1; }
.submit-body { flex:1; overflow-y:auto; padding:1.2rem; max-height:55vh; background:#fafafa; } .submit-body { flex:1; overflow-y:auto; padding:1rem; max-height:75vh; background:#fafafa; }
.submit-body .hint { font-size:0.75rem; color:#888; margin-bottom:1rem; line-height:1.5; } .submit-body .hint { font-size:0.75rem; color:#888; margin-bottom:1rem; line-height:1.5; }
.submit-body label { display:block; font-size:0.7rem; font-weight:600; color:#555; .submit-body label { display:block; font-size:0.7rem; font-weight:600; color:#555;
text-transform:uppercase; letter-spacing:0.03em; margin-bottom:0.2rem; margin-top:0.8rem; } text-transform:uppercase; letter-spacing:0.03em; margin-bottom:0.2rem; margin-top:0.8rem; }
@@ -1950,6 +1950,11 @@ def public_frontend():
.submit-body .submit-btn:disabled { opacity:0.5; cursor:default; } .submit-body .submit-btn:disabled { opacity:0.5; cursor:default; }
.submit-body .status-msg { text-align:center; font-size:0.8rem; margin-top:0.6rem; .submit-body .status-msg { text-align:center; font-size:0.8rem; margin-top:0.6rem;
min-height:1.2rem; } min-height:1.2rem; }
.capture-row { display:flex; gap:0.5rem; margin-top:0.3rem; }
.capture-btn { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:0.15rem; background:#fff; border:2px solid #ddd; border-radius:12px; padding:0.7rem 0.3rem; cursor:pointer; transition:all 0.15s; min-height:64px; -webkit-tap-highlight-color:transparent; touch-action:manipulation; }
.capture-btn:active { transform:scale(0.95); background:#f0f0f0; border-color:#20228a; }
.capture-icon { font-size:1.6rem; line-height:1; }
.capture-label { font-size:0.7rem; font-weight:600; color:#888; text-transform:uppercase; letter-spacing:0.04em; }
</style> </style>
</head> </head>
<body> <body>
@@ -2018,8 +2023,25 @@ def public_frontend():
<input type="text" id="subName" placeholder="Vorname oder Spitzname" maxlength="100"> <input type="text" id="subName" placeholder="Vorname oder Spitzname" maxlength="100">
<label>Nachricht (optional, reicht auch ohne Text)</label> <label>Nachricht (optional, reicht auch ohne Text)</label>
<textarea id="subText" placeholder="Was möchtest du mitteilen? ..." maxlength="5000"></textarea> <textarea id="subText" placeholder="Was möchtest du mitteilen? ..." maxlength="5000"></textarea>
<label>📎 Foto / Video / Audio (optional)</label> <label>📎 Medien aufnehmen oder auswählen</label>
<input type="file" id="subMedia" accept="image/*,video/*,audio/*"> <div class="capture-row">
<label class="capture-btn" id="capturePhotoBtn">
<input type="file" id="subPhoto" accept="image/*" capture="environment" hidden>
<span class="capture-icon">📸</span>
<span class="capture-label">Foto</span>
</label>
<label class="capture-btn" id="captureVideoBtn">
<input type="file" id="subVideo" accept="video/*" capture="environment" hidden>
<span class="capture-icon">🎬</span>
<span class="capture-label">Video</span>
</label>
<label class="capture-btn" id="captureAudioBtn">
<input type="file" id="subAudio" accept="audio/*" capture hidden>
<span class="capture-icon">🎤</span>
<span class="capture-label">Audio</span>
</label>
</div>
<input type="file" id="subGallery" accept="image/*,video/*,audio/*" style="margin-top:0.5rem;font-size:0.72rem;color:var(--text3);">
<label>📍 Halle / Stand (optional)</label> <label>📍 Halle / Stand (optional)</label>
<input type="text" id="subHalle" placeholder="z.B. H3 B123" maxlength="20"> <input type="text" id="subHalle" placeholder="z.B. H3 B123" maxlength="20">
<label>🎯 Spieltitel (optional)</label> <label>🎯 Spieltitel (optional)</label>
@@ -2049,8 +2071,8 @@ def public_frontend():
sSend.addEventListener('click', async () => { sSend.addEventListener('click', async () => {
const name = document.getElementById('subName').value.trim(); const name = document.getElementById('subName').value.trim();
const text = document.getElementById('subText').value.trim(); const text = document.getElementById('subText').value.trim();
const fileInput = document.getElementById('subMedia'); const fileInput = document.getElementById('subPhoto');
const file = fileInput.files[0]; const file = fileInput.files[0] || document.getElementById('subVideo').files[0] || document.getElementById('subAudio').files[0] || document.getElementById('subGallery').files[0];
const halle = document.getElementById('subHalle').value.trim(); const halle = document.getElementById('subHalle').value.trim();
const spiel = document.getElementById('subSpiel').value.trim(); const spiel = document.getElementById('subSpiel').value.trim();
@@ -2080,6 +2102,9 @@ def public_frontend():
document.getElementById('subName').value = ''; document.getElementById('subName').value = '';
document.getElementById('subText').value = ''; document.getElementById('subText').value = '';
fileInput.value = ''; fileInput.value = '';
document.getElementById('subVideo').value = '';
document.getElementById('subAudio').value = '';
document.getElementById('subGallery').value = '';
document.getElementById('subHalle').value = ''; document.getElementById('subHalle').value = '';
document.getElementById('subSpiel').value = ''; document.getElementById('subSpiel').value = '';
setTimeout(() => { sOverlay.classList.remove('open'); sOpen = false; sStatus.textContent = ''; }, 2500); setTimeout(() => { sOverlay.classList.remove('open'); sOpen = false; sStatus.textContent = ''; }, 2500);