WIP PWA for Grain
0
fork

Configure Feed

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

feat: add iOS install instructions to settings

- Detect iOS Safari and show "Add to Home Screen" instructions
- Add share icon for iOS instructions
- Hide instructions when already running as standalone app

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+38 -2
+2 -1
src/components/atoms/grain-icon.js
··· 15 15 plus: 'fa-solid fa-plus', 16 16 ellipsis: 'fa-solid fa-ellipsis', 17 17 ellipsisVertical: 'fa-solid fa-ellipsis-vertical', 18 - download: 'fa-solid fa-download' 18 + download: 'fa-solid fa-download', 19 + share: 'fa-solid fa-arrow-up-from-bracket' 19 20 }; 20 21 21 22 export class GrainIcon extends LitElement {
+23 -1
src/components/pages/grain-settings.js
··· 6 6 7 7 export class GrainSettings extends LitElement { 8 8 static properties = { 9 - _canInstall: { state: true } 9 + _canInstall: { state: true }, 10 + _showIOSInstructions: { state: true } 10 11 }; 11 12 static styles = css` 12 13 :host { ··· 70 71 .settings-row:active { 71 72 background: var(--color-bg-elevated); 72 73 } 74 + .ios-instructions { 75 + display: flex; 76 + align-items: flex-start; 77 + gap: var(--space-sm); 78 + padding: var(--space-md) var(--space-sm); 79 + border-bottom: 1px solid var(--color-border); 80 + color: var(--color-text-secondary); 81 + font-size: var(--font-size-sm); 82 + line-height: 1.4; 83 + } 84 + .ios-instructions grain-icon { 85 + flex-shrink: 0; 86 + margin-top: 2px; 87 + } 73 88 `; 74 89 75 90 #unsubscribe = null; ··· 77 92 connectedCallback() { 78 93 super.connectedCallback(); 79 94 this._canInstall = pwa.canInstall; 95 + this._showIOSInstructions = pwa.showIOSInstructions; 80 96 this.#unsubscribe = pwa.subscribe((canInstall) => { 81 97 this._canInstall = canInstall; 82 98 }); ··· 114 130 <grain-icon name="download" size="18"></grain-icon> 115 131 Install App 116 132 </button> 133 + ` : ''} 134 + ${this._showIOSInstructions ? html` 135 + <div class="ios-instructions"> 136 + <grain-icon name="share" size="18"></grain-icon> 137 + <span>To install, tap the share button in Safari and select "Add to Home Screen"</span> 138 + </div> 117 139 ` : ''} 118 140 <button class="settings-row" @click=${this.#signOut}> 119 141 <grain-icon name="logout" size="18"></grain-icon>
+13
src/services/pwa.js
··· 16 16 }); 17 17 } 18 18 19 + get isIOS() { 20 + return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 21 + } 22 + 23 + get isStandalone() { 24 + return window.matchMedia('(display-mode: standalone)').matches || 25 + window.navigator.standalone === true; 26 + } 27 + 19 28 get canInstall() { 20 29 return this.#deferredPrompt !== null; 30 + } 31 + 32 + get showIOSInstructions() { 33 + return this.isIOS && !this.isStandalone; 21 34 } 22 35 23 36 async install() {