Stand: SMTP-Test, Admin-Mail-Tab, Notifiable-Fix, Lazy-Quill
- Fix: Notifiable-Trait zum User-Model hinzugefuegt (behebt notify()-500er) - Installer: SMTP-Verbindungstest mit EsmtpTransport + Ueberspringen-Link - Admin: Neuer E-Mail-Tab mit SMTP-Konfiguration + Verbindungstest - Admin: Lazy Quill-Initialisierung (nur sichtbare Locale wird geladen) - Uebersetzungen: 17 neue Mail-Keys in allen 6 Sprachen Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
129
resources/views/components/pwa-install-banner.blade.php
Normal file
129
resources/views/components/pwa-install-banner.blade.php
Normal file
@@ -0,0 +1,129 @@
|
||||
{{-- PWA Install Banner (Android + iOS) --}}
|
||||
<div id="pwa-install-banner" style="display: none;">
|
||||
<style>
|
||||
#pwa-install-banner {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #1f2937;
|
||||
color: white;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
z-index: 9999;
|
||||
box-shadow: 0 -2px 10px rgba(0,0,0,0.15);
|
||||
}
|
||||
#pwa-install-banner .pwa-text {
|
||||
flex: 1;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
#pwa-install-banner .pwa-text strong {
|
||||
display: block;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
#pwa-install-banner .pwa-ios-steps {
|
||||
font-size: 0.82rem;
|
||||
margin-top: 0.3rem;
|
||||
color: rgba(255,255,255,0.85);
|
||||
}
|
||||
#pwa-install-banner .pwa-ios-steps .pwa-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
#pwa-install-banner button {
|
||||
border: none;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: 0.4rem;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#pwa-install-banner .pwa-install-btn {
|
||||
background: white;
|
||||
color: #1f2937;
|
||||
font-weight: 600;
|
||||
}
|
||||
#pwa-install-banner .pwa-dismiss-btn {
|
||||
background: transparent;
|
||||
color: rgba(255,255,255,0.8);
|
||||
padding: 0.6rem;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="pwa-text">
|
||||
<strong id="pwa-title">{{ __('ui.pwa_install_title') }}</strong>
|
||||
<span id="pwa-desc">{{ __('ui.pwa_install_text') }}</span>
|
||||
<div id="pwa-ios-steps" class="pwa-ios-steps" style="display: none;">
|
||||
{!! app(\App\Services\HtmlSanitizerService::class)->sanitize(__('ui.pwa_ios_steps')) !!}
|
||||
</div>
|
||||
</div>
|
||||
<button class="pwa-install-btn" id="pwa-install-btn">{{ __('ui.pwa_install_btn') }}</button>
|
||||
<button class="pwa-dismiss-btn" id="pwa-dismiss-btn">×</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
let deferredPrompt;
|
||||
const banner = document.getElementById('pwa-install-banner');
|
||||
const installBtn = document.getElementById('pwa-install-btn');
|
||||
const dismissBtn = document.getElementById('pwa-dismiss-btn');
|
||||
const iosSteps = document.getElementById('pwa-ios-steps');
|
||||
|
||||
const dismissed = localStorage.getItem('pwa-install-dismissed');
|
||||
const isStandalone = window.matchMedia('(display-mode: standalone)').matches
|
||||
|| window.navigator.standalone === true;
|
||||
|
||||
// Reset nach 30 Tagen
|
||||
if (dismissed && (Date.now() - parseInt(dismissed)) > 30 * 24 * 60 * 60 * 1000) {
|
||||
localStorage.removeItem('pwa-install-dismissed');
|
||||
}
|
||||
|
||||
// Bereits installiert → nichts anzeigen
|
||||
if (isStandalone) return;
|
||||
|
||||
// iOS-Erkennung (iPhone, iPad, iPod)
|
||||
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent)
|
||||
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
||||
|
||||
if (isIOS) {
|
||||
// iOS: Manuellen Hinweis zeigen (kein beforeinstallprompt)
|
||||
if (!dismissed) {
|
||||
installBtn.style.display = 'none';
|
||||
iosSteps.style.display = 'block';
|
||||
banner.style.display = 'flex';
|
||||
}
|
||||
} else {
|
||||
// Android/Chrome: beforeinstallprompt abfangen
|
||||
window.addEventListener('beforeinstallprompt', (e) => {
|
||||
e.preventDefault();
|
||||
deferredPrompt = e;
|
||||
|
||||
if (!dismissed) {
|
||||
banner.style.display = 'flex';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
installBtn.addEventListener('click', async () => {
|
||||
if (!deferredPrompt) return;
|
||||
|
||||
deferredPrompt.prompt();
|
||||
await deferredPrompt.userChoice;
|
||||
|
||||
deferredPrompt = null;
|
||||
banner.style.display = 'none';
|
||||
});
|
||||
|
||||
dismissBtn.addEventListener('click', () => {
|
||||
banner.style.display = 'none';
|
||||
localStorage.setItem('pwa-install-dismissed', Date.now());
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user