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
105 lines
2.9 KiB
Vue
105 lines
2.9 KiB
Vue
<template>
|
|
<Transition
|
|
enter-active-class="transition ease-out duration-300"
|
|
enter-from-class="opacity-0 translate-y-2"
|
|
enter-to-class="opacity-100 translate-y-0"
|
|
leave-active-class="transition ease-in duration-200"
|
|
leave-from-class="opacity-100 translate-y-0"
|
|
leave-to-class="opacity-0 translate-y-2"
|
|
>
|
|
<div
|
|
v-if="showPrompt"
|
|
class="fixed bottom-4 left-4 right-4 md:left-auto md:right-4 md:max-w-md z-50"
|
|
>
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-2xl border border-gray-200 dark:border-gray-700 p-4">
|
|
<div class="flex items-start gap-4">
|
|
<!-- App Icon -->
|
|
<div class="flex-shrink-0">
|
|
<img
|
|
src="/icon-192x192.png"
|
|
alt="Pantry icon"
|
|
class="w-16 h-16 rounded-lg shadow-md"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="flex-1 min-w-0">
|
|
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-1">
|
|
Install Pantry
|
|
</h3>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
|
|
Install this app for quick access and offline use
|
|
</p>
|
|
|
|
<!-- Actions -->
|
|
<div class="flex gap-2">
|
|
<UButton
|
|
color="emerald"
|
|
size="sm"
|
|
@click="install"
|
|
:loading="installing"
|
|
>
|
|
<template #leading>
|
|
<UIcon name="i-heroicons-arrow-down-tray" />
|
|
</template>
|
|
Install
|
|
</UButton>
|
|
|
|
<UButton
|
|
color="gray"
|
|
variant="ghost"
|
|
size="sm"
|
|
@click="dismiss"
|
|
>
|
|
Not now
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Close button -->
|
|
<button
|
|
@click="dismiss"
|
|
class="flex-shrink-0 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition"
|
|
>
|
|
<UIcon name="i-heroicons-x-mark" class="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
const { canInstall, promptInstall, dismissInstall, shouldShowPrompt } = usePWAInstall()
|
|
const installing = ref(false)
|
|
const showPrompt = ref(false)
|
|
|
|
// Show prompt after a delay if conditions are met
|
|
onMounted(() => {
|
|
setTimeout(() => {
|
|
if (shouldShowPrompt()) {
|
|
showPrompt.value = true
|
|
}
|
|
}, 3000) // Wait 3 seconds after page load
|
|
})
|
|
|
|
async function install() {
|
|
installing.value = true
|
|
try {
|
|
const { outcome } = await promptInstall()
|
|
if (outcome === 'accepted') {
|
|
showPrompt.value = false
|
|
}
|
|
} catch (error) {
|
|
console.error('Install failed:', error)
|
|
} finally {
|
|
installing.value = false
|
|
}
|
|
}
|
|
|
|
function dismiss() {
|
|
dismissInstall()
|
|
showPrompt.value = false
|
|
}
|
|
</script>
|