WIP PWA for Grain
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: add haptic feedback implementation plan

+172
+172
docs/plans/2026-01-04-haptic-feedback.md
··· 1 + # Haptic Feedback Implementation Plan 2 + 3 + > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. 4 + 5 + **Goal:** Add haptic feedback to bottom navigation taps for iOS 18+ and Android PWA users. 6 + 7 + **Architecture:** A small utility module (`haptics.js`) that uses the iOS 18 checkbox-switch hack for Safari and falls back to `navigator.vibrate()` for Android. The bottom nav component imports and calls the trigger function in each navigation handler. 8 + 9 + **Tech Stack:** Vanilla JS, Lit elements, Web Vibration API, iOS 18 checkbox switch attribute 10 + 11 + --- 12 + 13 + ### Task 1: Create Haptics Utility 14 + 15 + **Files:** 16 + - Create: `src/utils/haptics.js` 17 + 18 + **Step 1: Create the haptics utility file** 19 + 20 + ```js 21 + /** 22 + * Haptic feedback utility for PWA 23 + * - iOS 18+: Uses checkbox switch element hack 24 + * - Android: Uses Vibration API 25 + * - Other: Silently does nothing 26 + */ 27 + 28 + // Platform detection 29 + const isIOS = /iPhone|iPad/.test(navigator.userAgent); 30 + const hasVibrate = 'vibrate' in navigator; 31 + 32 + // Lazy-initialized hidden elements for iOS 33 + let checkbox = null; 34 + let label = null; 35 + 36 + function ensureElements() { 37 + if (checkbox) return; 38 + 39 + checkbox = document.createElement('input'); 40 + checkbox.type = 'checkbox'; 41 + checkbox.setAttribute('switch', ''); 42 + checkbox.id = 'haptic-trigger'; 43 + checkbox.style.cssText = 'position:fixed;left:-9999px;opacity:0;pointer-events:none;'; 44 + 45 + label = document.createElement('label'); 46 + label.htmlFor = 'haptic-trigger'; 47 + label.style.cssText = 'position:fixed;left:-9999px;opacity:0;pointer-events:none;'; 48 + 49 + document.body.append(checkbox, label); 50 + } 51 + 52 + /** 53 + * Trigger a light haptic tap 54 + */ 55 + export function trigger() { 56 + if (isIOS) { 57 + ensureElements(); 58 + label.click(); 59 + } else if (hasVibrate) { 60 + navigator.vibrate(10); 61 + } 62 + } 63 + 64 + /** 65 + * Check if haptics are supported on this device 66 + */ 67 + export function isSupported() { 68 + return isIOS || hasVibrate; 69 + } 70 + ``` 71 + 72 + **Step 2: Commit the utility** 73 + 74 + ```bash 75 + git add src/utils/haptics.js 76 + git commit -m "feat: add haptics utility for iOS 18+ and Android" 77 + ``` 78 + 79 + --- 80 + 81 + ### Task 2: Integrate Haptics into Bottom Nav 82 + 83 + **Files:** 84 + - Modify: `src/components/organisms/grain-bottom-nav.js` 85 + 86 + **Step 1: Add the import** 87 + 88 + At the top of the file with other imports, add: 89 + 90 + ```js 91 + import { trigger as haptic } from '../../utils/haptics.js'; 92 + ``` 93 + 94 + **Step 2: Add haptic calls to navigation handlers** 95 + 96 + Find each handler method and add `haptic();` as the first line: 97 + 98 + ```js 99 + #handleHome() { 100 + haptic(); 101 + router.push('/'); 102 + } 103 + 104 + #handleProfile() { 105 + haptic(); 106 + router.push(`/profile/${this._user.handle}`); 107 + } 108 + 109 + #handleExplore() { 110 + haptic(); 111 + router.push('/explore'); 112 + } 113 + 114 + #handleNotifications() { 115 + haptic(); 116 + router.push('/notifications'); 117 + } 118 + 119 + #handleCreate() { 120 + haptic(); 121 + this._fileInput.click(); 122 + } 123 + ``` 124 + 125 + **Step 3: Commit the integration** 126 + 127 + ```bash 128 + git add src/components/organisms/grain-bottom-nav.js 129 + git commit -m "feat: add haptic feedback to bottom nav taps" 130 + ``` 131 + 132 + --- 133 + 134 + ### Task 3: Manual Testing 135 + 136 + **Step 1: Start the dev server** 137 + 138 + ```bash 139 + npm run dev 140 + ``` 141 + 142 + **Step 2: Test on iOS 18+ device** 143 + 144 + - Open the app in Safari on iPhone/iPad running iOS 18+ 145 + - Add to Home Screen (PWA mode) 146 + - Tap each bottom nav item 147 + - Expected: Light haptic tap on each navigation 148 + 149 + **Step 3: Test on Android device** 150 + 151 + - Open the app in Chrome on Android 152 + - Add to Home Screen or test in browser 153 + - Tap each bottom nav item 154 + - Expected: Light vibration (10ms) on each navigation 155 + 156 + **Step 4: Test on desktop** 157 + 158 + - Open the app in any desktop browser 159 + - Click each bottom nav item 160 + - Expected: No errors, navigation works normally, no haptic (graceful degradation) 161 + 162 + --- 163 + 164 + ## Summary 165 + 166 + | Task | Description | Files | 167 + |------|-------------|-------| 168 + | 1 | Create haptics utility | `src/utils/haptics.js` | 169 + | 2 | Integrate into bottom nav | `src/components/organisms/grain-bottom-nav.js` | 170 + | 3 | Manual testing | N/A | 171 + 172 + **Total changes:** 2 files, ~40 lines of code