🎯

pwa-setup

🎯Skill

from dadbodgeoff/drift

VibeIndex|
What it does

Configures Progressive Web App settings with manifest, meta tags, safe areas, and install prompts for a native-like mobile web experience.

πŸ“¦

Part of

dadbodgeoff/drift(69 items)

pwa-setup

Installation

npm installInstall npm package
npm install -g driftdetect
npm installInstall npm package
npm install -g driftdetect@latest
npm installInstall npm package
npm install -g driftdetect-mcp
Claude Desktop ConfigurationAdd this to your claude_desktop_config.json
{ "mcpServers": { "drift": { "command": "driftdetect-mcp" } } ...
πŸ“– Extracted from docs: dadbodgeoff/drift
4Installs
-
AddedFeb 4, 2026

Skill Details

SKILL.md

Progressive Web App setup with manifest, mobile meta tags, safe area handling for notched devices, and install prompts for app-like browser experience.

Overview

# PWA Setup

Progressive Web App configuration for app-like browser experience.

When to Use This Skill

  • Users want to "install" your web app
  • Mobile users want home screen access
  • Need app-like behavior without native apps
  • Supporting notched devices (iPhone, etc.)

Core Concepts

PWA requires:

  1. Web App Manifest - App metadata and icons
  2. Mobile meta tags - Viewport and theme configuration
  3. Safe areas - Handle notched devices
  4. Install prompt - Custom install experience

Implementation

TypeScript (Next.js)

```typescript

// app/manifest.ts

import type { MetadataRoute } from 'next';

export default function manifest(): MetadataRoute.Manifest {

return {

name: "My SaaS App",

short_name: "MySaaS",

description: "Your app description here",

start_url: '/dashboard',

display: 'standalone',

background_color: '#0f172a',

theme_color: '#14b8a6',

orientation: 'portrait-primary',

icons: [

{

src: '/icons/icon-192.png',

sizes: '192x192',

type: 'image/png',

purpose: 'any',

},

{

src: '/icons/icon-512.png',

sizes: '512x512',

type: 'image/png',

purpose: 'any',

},

{

src: '/icons/icon-maskable.png',

sizes: '512x512',

type: 'image/png',

purpose: 'maskable',

},

],

shortcuts: [

{ name: 'Dashboard', url: '/dashboard', description: 'Go to dashboard' },

{ name: 'Settings', url: '/settings', description: 'App settings' },

],

categories: ['productivity', 'utilities'],

};

}

```

Root Layout Metadata

```typescript

// app/layout.tsx

import type { Metadata, Viewport } from 'next';

export const metadata: Metadata = {

title: "My SaaS App",

description: "Your app description",

appleWebApp: {

capable: true,

statusBarStyle: 'black-translucent',

title: "MySaaS",

},

applicationName: "MySaaS",

openGraph: {

title: "My SaaS App",

description: "Your app description",

type: 'website',

siteName: "MySaaS",

},

};

export const viewport: Viewport = {

width: 'device-width',

initialScale: 1,

maximumScale: 1,

userScalable: false,

themeColor: '#14b8a6',

viewportFit: 'cover',

};

export default function RootLayout({ children }: { children: React.ReactNode }) {

return (

{children}

);

}

```

Safe Area CSS

```css

/ globals.css /

/ Safe area for bottom navigation (notched devices) /

.safe-area-bottom {

padding-bottom: env(safe-area-inset-bottom, 0);

}

/ Safe area for top header /

.safe-area-top {

padding-top: env(safe-area-inset-top, 0);

}

/ Full safe area padding /

.safe-area-all {

padding-top: env(safe-area-inset-top, 0);

padding-right: env(safe-area-inset-right, 0);

padding-bottom: env(safe-area-inset-bottom, 0);

padding-left: env(safe-area-inset-left, 0);

}

```

Install Prompt Hook

```typescript

// hooks/useInstallPrompt.ts

'use client';

import { useState, useEffect } from 'react';

interface BeforeInstallPromptEvent extends Event {

prompt: () => Promise;

userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;

}

export function useInstallPrompt() {

const [installPrompt, setInstallPrompt] = useState(null);

const [isInstalled, setIsInstalled] = useState(false);

useEffect(() => {

if (window.matchMedia('(display-mode: standalone)').matches) {

setIsInstalled(true);

return;

}

const handler = (e: Event) => {

e.preventDefault();

setInstallPrompt(e as BeforeInstallPromptEvent);

};

window.addEventListener('beforeinstallprompt', handler);

return () => window.removeEventListener('beforeinstallprompt', handler);

}, []);

const promptInstall = async () => {

if (!installPrompt) return false;

await installPrompt.prompt();

const { outcome } = await installPrompt.userChoice;

if (outcome === 'accepted') {

setIsInstalled(true);

setInstallPrompt(null);

}

return outcome === 'accepted';

};

return {

canInstall: !!installPrompt && !isInstalled,

isInstalled,

promptInstall,

};

}

```

Install Banner Component

```typescript

// components/InstallBanner.tsx

'use client';

import { useInstallPrompt } from '@/hooks/useInstallPrompt';

export function InstallBanner() {

const { canInstall, promptInstall } = useInstallPrompt();

if (!canInstall) return null;

return (

Install our app for a better experience

onClick={promptInstall}

className="w-full py-2 bg-white text-primary-600 rounded font-medium"

>

Install App

);

}

```

Mobile Navigation with Safe Area

```typescript

// components/MobileNav.tsx

export function MobileNav() {

return (

);

}

```

Icon Requirements

```

public/

β”œβ”€β”€ icons/

β”‚ β”œβ”€β”€ icon-192.png # Standard icon

β”‚ β”œβ”€β”€ icon-512.png # Large icon

β”‚ └── icon-maskable.png # Maskable (with safe zone padding)

β”œβ”€β”€ favicon.ico

└── apple-touch-icon.png # 180x180 for iOS

```

Maskable Icon Safe Zone

```

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”

β”‚ β”‚

β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚

β”‚ β”‚ LOGO β”‚ β”‚ ← Content in center 80%

β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚

β”‚ β”‚

β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

```

Usage Examples

Testing PWA

  1. Chrome DevTools β†’ Application β†’ Manifest
  2. Lighthouse β†’ PWA audit
  3. Mobile β†’ Add to Home Screen

Detecting Standalone Mode

```typescript

function isStandalone(): boolean {

return window.matchMedia('(display-mode: standalone)').matches ||

(window.navigator as any).standalone === true;

}

```

Best Practices

  1. Use maskable icons with safe zone
  2. Set theme_color to match your brand
  3. Handle safe areas for notched devices
  4. Provide install prompt at appropriate time
  5. Test on actual mobile devices

Common Mistakes

  • Missing maskable icon (ugly on Android)
  • No safe area handling (content under notch)
  • Install prompt shown immediately (annoying)
  • Wrong start_url (opens wrong page)
  • Missing apple-touch-icon (iOS fallback)

Related Patterns

  • design-tokens - Consistent theming
  • mobile-components - Responsive components

More from this repository10

🎯
feature-flags🎯Skill

Enables controlled feature rollouts, A/B testing, and selective feature access through configurable flags for gradual deployment and user targeting.

🎯
design-tokens🎯Skill

Generates a comprehensive, type-safe design token system with WCAG AA color compliance and multi-framework support for consistent visual design.

🎯
file-uploads🎯Skill

Securely validates, scans, and processes file uploads with multi-stage checks, malware detection, and race condition prevention.

🎯
ai-coaching🎯Skill

Guides users through articulating creative intent by extracting structured parameters and detecting conversation readiness.

🎯
environment-config🎯Skill

Validates and centralizes environment variables with type safety, fail-fast startup checks, and multi-environment support.

🎯
community-feed🎯Skill

Generates efficient social feed with cursor pagination, trending algorithms, and engagement tracking for infinite scroll experiences.

🎯
cloud-storage🎯Skill

Enables secure, multi-tenant cloud file storage with signed URLs, direct uploads, and visibility control for user-uploaded assets.

🎯
email-service🎯Skill

Simplifies email sending, templating, and tracking with robust SMTP integration and support for multiple email providers and transactional workflows.

🎯
error-sanitization🎯Skill

Sanitizes error messages by logging full details server-side while exposing only generic, safe messages to prevent sensitive information leakage.

🎯
batch-processing🎯Skill

Optimizes database operations by collecting and batching independent records, improving throughput by 30-40% with built-in fallback processing.