Some checks failed
Deploy to Coolify / Code Quality (pull_request) Has been cancelled
Deploy to Coolify / Run Tests (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Development (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Production (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Test (pull_request) Has been cancelled
Pull Request Checks / Validate PR (pull_request) Has been cancelled
- Create usePWAInstall composable for install management - Add InstallPrompt banner component with auto-show after 3s - Add App Settings tab in settings page - Show install button with loading state - Display installation status and instructions - Handle dismissal with 7-day cooldown - Add iOS/Android installation guides - Show PWA features list - Display storage usage with visual progress - Auto-hide prompt after successful install Features: - Automatic install prompt after 3 seconds - Manual install from settings - Platform-specific instructions - Smart dismissal tracking - Storage info visualization Closes #35
94 lines
2.2 KiB
TypeScript
94 lines
2.2 KiB
TypeScript
/**
|
|
* Composable to handle PWA installation
|
|
*
|
|
* Usage:
|
|
* const { canInstall, isInstalled, promptInstall, dismissInstall } = usePWAInstall()
|
|
*/
|
|
export function usePWAInstall() {
|
|
const canInstall = ref(false)
|
|
const isInstalled = ref(false)
|
|
const deferredPrompt = ref<any>(null)
|
|
|
|
if (process.client) {
|
|
// Check if already installed
|
|
if (window.matchMedia('(display-mode: standalone)').matches) {
|
|
isInstalled.value = true
|
|
}
|
|
|
|
// Listen for beforeinstallprompt event
|
|
window.addEventListener('beforeinstallprompt', (e) => {
|
|
// Prevent the mini-infobar from appearing on mobile
|
|
e.preventDefault()
|
|
|
|
// Stash the event so it can be triggered later
|
|
deferredPrompt.value = e
|
|
canInstall.value = true
|
|
})
|
|
|
|
// Listen for appinstalled event
|
|
window.addEventListener('appinstalled', () => {
|
|
isInstalled.value = true
|
|
canInstall.value = false
|
|
deferredPrompt.value = null
|
|
})
|
|
}
|
|
|
|
async function promptInstall() {
|
|
if (!deferredPrompt.value) {
|
|
return { outcome: 'not-available' }
|
|
}
|
|
|
|
// Show the install prompt
|
|
deferredPrompt.value.prompt()
|
|
|
|
// Wait for the user to respond to the prompt
|
|
const { outcome } = await deferredPrompt.value.userChoice
|
|
|
|
// Clear the deferredPrompt
|
|
deferredPrompt.value = null
|
|
|
|
if (outcome === 'accepted') {
|
|
canInstall.value = false
|
|
}
|
|
|
|
return { outcome }
|
|
}
|
|
|
|
function dismissInstall() {
|
|
canInstall.value = false
|
|
deferredPrompt.value = null
|
|
|
|
// Remember dismissal for 7 days
|
|
if (process.client) {
|
|
localStorage.setItem('pwa-install-dismissed', Date.now().toString())
|
|
}
|
|
}
|
|
|
|
function shouldShowPrompt() {
|
|
if (!canInstall.value || isInstalled.value) {
|
|
return false
|
|
}
|
|
|
|
if (process.client) {
|
|
const dismissed = localStorage.getItem('pwa-install-dismissed')
|
|
if (dismissed) {
|
|
const dismissedTime = parseInt(dismissed)
|
|
const sevenDays = 7 * 24 * 60 * 60 * 1000
|
|
if (Date.now() - dismissedTime < sevenDays) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
return {
|
|
canInstall: readonly(canInstall),
|
|
isInstalled: readonly(isInstalled),
|
|
promptInstall,
|
|
dismissInstall,
|
|
shouldShowPrompt
|
|
}
|
|
}
|