Swoff Swoff

Components

UI components for Swoff — UpdatePrompt, SWProgressBar, InstallButton.

Vue Components

These components use Vue composables to provide ready-to-use UI elements. See Component Specs for behavioral details.

UpdatePrompt

@/components/UpdatePrompt.vue
<script setup>
import { useSWUpdate } from "../composables/useSWUpdate";

const {
  updateStatus,
  currentVersion,
  availableVersion,
  progress,
  forceUpdate,
  acceptUpdate,
  dismissUpdate,
} = useSWUpdate();
</script>

<template>
  <div
    v-if="updateStatus !== 'idle'"
    :class="['update-prompt', forceUpdate ? 'fullscreen' : 'bottom-sheet']"
  >
    <p>Update available: v{{ currentVersion }} → v{{ availableVersion }}</p>
    <div
      v-if="updateStatus === 'downloading'"
      class="progress-bar"
      :style="{ width: `${progress}%` }"
    />
    <template v-else>
      <button @click="acceptUpdate">Update</button>
      <button v-if="!forceUpdate" @click="dismissUpdate">Later</button>
    </template>
  </div>
</template>

SWProgressBar

@/components/SWProgressBar.vue
<script setup>
import { useSWProgress } from "../composables/useSWProgress";

const { progress, status } = useSWProgress();
</script>

<template>
  <div
    v-if="status === 'installing'"
    class="fixed top-0 left-0 w-full h-1 bg-gray-200"
  >
    <div
      class="h-full bg-blue-500 transition-all"
      :style="{ width: `${progress}%` }"
    />
  </div>
</template>

InstallButton

@/components/InstallButton.vue
<script setup>
import { ref, onMounted } from "vue";

const deferredPrompt = ref(null);

onMounted(() => {
  window.addEventListener("beforeinstallprompt", (e) => {
    e.preventDefault();
    deferredPrompt.value = e;
  });
});

const handleInstall = async () => {
  if (!deferredPrompt.value) return;
  deferredPrompt.value.prompt();
  const { outcome } = await deferredPrompt.value.userChoice;
  if (outcome === "accepted") deferredPrompt.value = null;
};
</script>

<template>
  <button v-if="deferredPrompt" @click="handleInstall">Install App</button>
</template>

Next Steps

On this page