SavvySolve Docs

PWA & Mobile Experience

Progressive Web App configuration and mobile-first responsive design patterns

PWA & Mobile Experience

SavvySolve is built as a Progressive Web App (PWA) with mobile-first design principles. This means users can install the app on their home screen and use it like a native application, which is particularly important for our target audience of seniors who may be more comfortable with app-like experiences than browser tabs.

Progressive Web App

The PWA configuration enables users to "Add to Home Screen" on both iOS and Android devices. Once installed, SavvySolve launches in standalone mode without browser chrome, providing a native app experience.

Web App Manifest

The manifest file defines how the app appears when installed on a user's device.

public/manifest.json
{
  "name": "SavvySolve - On-Demand Tech Support",
  "short_name": "SavvySolve",
  "description": "The DoorDash of getting things done digitally.",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#FFFFFF",
  "theme_color": "#1B0F40",
  "orientation": "portrait-primary",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "/icons/icon-maskable-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

Key configuration choices:

  • display: standalone removes the browser UI, making the app feel native
  • theme_color: #1B0F40 (SavvySolve purple) colors the status bar on Android
  • orientation: portrait-primary optimizes for phone usage patterns
  • Maskable icons ensure proper display on Android devices with adaptive icon shapes

Next.js Metadata Integration

The manifest and PWA metadata are configured in the root layout using Next.js 13+ metadata API.

app/layout.tsx
export const metadata: Metadata = {
  title: "SavvySolve",
  description: "The DoorDash of getting things done digitally.",
  manifest: "/manifest.json",
  themeColor: "#1B0F40",
  appleWebApp: {
    capable: true,
    statusBarStyle: "default",
    title: "SavvySolve",
  },
  icons: {
    icon: [
      { url: "/icons/favicon-16x16.png", sizes: "16x16", type: "image/png" },
      { url: "/icons/favicon-32x32.png", sizes: "32x32", type: "image/png" },
    ],
    apple: [
      { url: "/icons/apple-touch-icon.png", sizes: "180x180", type: "image/png" },
    ],
  },
};

App Shortcuts

The manifest includes shortcuts that appear when users long-press the app icon.

public/manifest.json (shortcuts section)
{
  "shortcuts": [
    {
      "name": "Get Help",
      "short_name": "Help",
      "description": "Submit a new support request",
      "url": "/?action=new"
    },
    {
      "name": "Dashboard",
      "short_name": "Dashboard", 
      "description": "View your dashboard",
      "url": "/dashboard"
    }
  ]
}

Icon Generation

PWA icons are generated from a single SVG source using a build script.

scripts/generate-pwa-icons.ts
import sharp from "sharp";

const ICON_SIZES = [72, 96, 128, 144, 152, 192, 384, 512];

async function generateIcons() {
  for (const size of ICON_SIZES) {
    await sharp("public/icons/icon.svg")
      .resize(size, size)
      .png()
      .toFile(`public/icons/icon-${size}x${size}.png`);
  }
}

Run bun run scripts/generate-pwa-icons.ts after modifying the source SVG.

Mobile-First Touch Targets

Following WCAG AAA guidelines for touch accessibility, all interactive elements have a minimum touch target of 44x44 pixels on mobile devices. This is especially important for our senior user demographic.

Responsive Component Sizing

UI components use mobile-first sizing that reduces on larger screens.

components/ui/button.tsx
const buttonVariants = cva(
  "... touch-manipulation",
  {
    variants: {
      size: {
        // Mobile-first: 44px minimum, smaller on desktop
        default: "min-h-11 px-4 py-2 md:min-h-9",
        sm: "min-h-11 px-3 md:min-h-8",
        icon: "min-h-11 min-w-11 md:size-9",
      },
    },
  }
);

The touch-manipulation CSS class eliminates the 300ms tap delay on mobile browsers.

Input Components

Form inputs follow the same pattern with comfortable touch targets on mobile.

components/ui/input.tsx
<input
  className={cn(
    // Mobile: 44px height, comfortable padding
    "min-h-11 px-3 py-2 text-base",
    // Desktop: smaller, tighter
    "md:min-h-9 md:py-1 md:text-sm",
    "touch-manipulation",
  )}
/>

Using text-base (16px) on mobile prevents iOS from zooming in when focusing inputs.

Responsive Layout System

The dashboard uses a responsive breakpoint strategy optimized for tablets and phones.

Breakpoint Strategy

BreakpointWidthUsage
Default0-639pxMobile phones - single column, bottom nav
sm640px+Large phones - 2 columns where appropriate
md768px+Small tablets - still use bottom nav
lg1024px+Tablets/desktop - sidebar navigation

The sidebar appears only on large screens (1024px+), while mobile and tablet users see the bottom navigation bar.

app/(authenticated)/layout.tsx
<div className="flex h-screen">
  {/* Sidebar: hidden until lg breakpoint */}
  <Sidebar className="hidden lg:flex" />
  
  <div className="flex flex-1 flex-col">
    <main className="flex-1 p-4 pb-20 lg:p-6 lg:pb-6">
      {children}
    </main>
  </div>
  
  {/* Bottom nav: visible until lg breakpoint */}
  <BottomNav className="lg:hidden" />
</div>

The extra bottom padding (pb-20) on mobile accounts for the fixed bottom navigation bar.

Session Interface Grid

Complex layouts like the session interface adapt to screen size.

components/session/SessionInterface.tsx
<div className="grid gap-4 sm:gap-6 md:grid-cols-2 lg:grid-cols-3">
  {/* Timer */}
  <div>
    <SessionTimer />
  </div>
  
  {/* Chat - responsive height */}
  <div>
    <ChatWindow className="h-[400px] sm:h-[450px] lg:h-[500px]" />
  </div>
  
  {/* Notes - spans 2 cols on tablet */}
  <div className="md:col-span-2 lg:col-span-1">
    <SessionNotes />
  </div>
</div>

This creates:

  • Mobile: Single column, stacked vertically
  • Tablet (md): 2 columns with notes spanning full width below
  • Desktop (lg): 3 equal columns side by side

Testing the PWA

Chrome DevTools

  1. Open DevTools → Application → Manifest
  2. Verify all icons load correctly
  3. Check "Installable" status in Lighthouse audit

Installing on Devices

iOS Safari:

  1. Navigate to the app
  2. Tap Share button
  3. Select "Add to Home Screen"

Android Chrome:

  1. Navigate to the app
  2. Tap menu (three dots)
  3. Select "Install app" or "Add to Home Screen"

Lighthouse Audit

Run a Lighthouse PWA audit to verify:

  • Manifest is valid and complete
  • Icons are correct sizes
  • Theme color is set
  • App is installable

The app should pass all PWA installability checks.

Future Enhancements

The current PWA implementation enables installation but does not include offline support. Future improvements could include:

  • Service Worker: Cache static assets for offline access
  • Background Sync: Queue messages when offline
  • Push Notifications: Alert users to new messages or session updates

These would require additional configuration with Next.js and a service worker registration strategy.

On this page