Complete PWA implementation with custom icons
- Add PWA icons in multiple sizes (192px, 512px, maskable) - Configure manifest.webmanifest with proper icon references - Implement PWA install prompt with custom notification - Add manual manifest route for development compatibility - Update meta tags for iOS and Android PWA support - Configure service worker with music and image caching - Enable auto-updates and offline functionality PWA now fully installable on all platforms with proper branding.
This commit is contained in:
168
plugins/pwa-install.client.ts
Normal file
168
plugins/pwa-install.client.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
export default defineNuxtPlugin(() => {
|
||||
if (process.client) {
|
||||
let deferredPrompt: any = null
|
||||
|
||||
// Listen for PWA install prompt
|
||||
window.addEventListener('beforeinstallprompt', (e) => {
|
||||
console.log('[PWA] Install prompt available')
|
||||
e.preventDefault()
|
||||
deferredPrompt = e
|
||||
|
||||
// Show custom install button or notification
|
||||
showInstallNotification()
|
||||
})
|
||||
|
||||
// Listen for successful installation
|
||||
window.addEventListener('appinstalled', () => {
|
||||
console.log('[PWA] App successfully installed')
|
||||
deferredPrompt = null
|
||||
|
||||
// Hide install notification
|
||||
hideInstallNotification()
|
||||
|
||||
// Show success message
|
||||
showInstallSuccess()
|
||||
})
|
||||
|
||||
// Function to trigger install
|
||||
const installPWA = async () => {
|
||||
if (!deferredPrompt) {
|
||||
console.log('[PWA] No install prompt available')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
deferredPrompt.prompt()
|
||||
const { outcome } = await deferredPrompt.userChoice
|
||||
|
||||
if (outcome === 'accepted') {
|
||||
console.log('[PWA] User accepted install')
|
||||
} else {
|
||||
console.log('[PWA] User dismissed install')
|
||||
}
|
||||
|
||||
deferredPrompt = null
|
||||
} catch (error) {
|
||||
console.error('[PWA] Install error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Show install notification
|
||||
const showInstallNotification = () => {
|
||||
// Create install notification if it doesn't exist
|
||||
if (!document.getElementById('pwa-install-notification')) {
|
||||
const notification = document.createElement('div')
|
||||
notification.id = 'pwa-install-notification'
|
||||
notification.innerHTML = `
|
||||
<div style="
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: linear-gradient(45deg, #8b5cf6, #06b6d4);
|
||||
color: white;
|
||||
padding: 16px 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
z-index: 9999;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
max-width: 320px;
|
||||
animation: slideIn 0.3s ease-out;
|
||||
">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div style="font-size: 24px;">🎵</div>
|
||||
<div>
|
||||
<div style="font-weight: 600; margin-bottom: 4px;">¡Instalar RepoDructor!</div>
|
||||
<div style="font-size: 14px; opacity: 0.9;">Accede rápidamente a tu música</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 12px; display: flex; gap: 8px;">
|
||||
<button id="pwa-install-btn" style="
|
||||
background: rgba(255,255,255,0.2);
|
||||
color: white;
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
">Instalar</button>
|
||||
<button id="pwa-dismiss-btn" style="
|
||||
background: transparent;
|
||||
color: rgba(255,255,255,0.8);
|
||||
border: none;
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
">Ahora no</button>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
// Add CSS animation
|
||||
const style = document.createElement('style')
|
||||
style.textContent = `
|
||||
@keyframes slideIn {
|
||||
from { transform: translateX(100%); opacity: 0; }
|
||||
to { transform: translateX(0); opacity: 1; }
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
|
||||
document.body.appendChild(notification)
|
||||
|
||||
// Add event listeners
|
||||
document.getElementById('pwa-install-btn')?.addEventListener('click', installPWA)
|
||||
document.getElementById('pwa-dismiss-btn')?.addEventListener('click', hideInstallNotification)
|
||||
}
|
||||
}
|
||||
|
||||
// Hide install notification
|
||||
const hideInstallNotification = () => {
|
||||
const notification = document.getElementById('pwa-install-notification')
|
||||
if (notification) {
|
||||
notification.remove()
|
||||
}
|
||||
}
|
||||
|
||||
// Show success message
|
||||
const showInstallSuccess = () => {
|
||||
const success = document.createElement('div')
|
||||
success.innerHTML = `
|
||||
<div style="
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: linear-gradient(45deg, #10b981, #06b6d4);
|
||||
color: white;
|
||||
padding: 16px 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
z-index: 9999;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
animation: slideIn 0.3s ease-out;
|
||||
">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div style="font-size: 24px;">✅</div>
|
||||
<div>
|
||||
<div style="font-weight: 600;">¡App instalada!</div>
|
||||
<div style="font-size: 14px; opacity: 0.9;">RepoDructor está ahora en tu dispositivo</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
document.body.appendChild(success)
|
||||
|
||||
// Remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
success.remove()
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
// Make install function globally available
|
||||
;(window as any).installRepoDructorPWA = installPWA
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user