index.html (15.6 KB)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>💡</text></svg>"> 7 <title>PWA Installation Guide</title> 8 <style> 9 html { 10 scroll-behavior: smooth; 11 } 12 13 body { 14 font-family: sans-serif; 15 max-width: 800px; 16 margin: 0 auto; 17 padding: 20px; 18 background-color: #f5f5f5; 19 color: #333; 20 line-height: 1.6; 21 } 22 23 h1 { 24 text-align: center; 25 border-bottom: 3px double #333; 26 padding-bottom: 10px; 27 margin-bottom: 30px; 28 } 29 30 .subtitle { 31 text-align: center; 32 margin-bottom: 30px; 33 } 34 35 h2 { 36 border-bottom: 1px solid #666; 37 padding-bottom: 5px; 38 margin-top: 0; 39 } 40 41 .toc { 42 border: 1px solid #ccc; 43 padding: 15px; 44 margin: 20px 0; 45 background-color: #fff; 46 } 47 48 .toc h3 { 49 margin-top: 0; 50 text-decoration: underline; 51 } 52 53 .toc ul { 54 margin: 10px 0; 55 padding-left: 20px; 56 } 57 58 59 a { 60 color: #0000EE; 61 text-decoration: underline; 62 } 63 64 a:visited { 65 color: #0000EE; 66 } 67 68 a.auto-detected, 69 a.auto-detected:visited { 70 background: linear-gradient(to top right, #64b5f6 0%, #e3f2fd 100%); 71 padding: 12px; 72 font-weight: bold; 73 font-size: 1.15em; 74 display: none; 75 text-align: center; 76 cursor: pointer; 77 border-radius: 12px; 78 text-decoration: none; 79 color: #ffffff; 80 } 81 82 .auto-detected p { 83 padding: 10px; 84 } 85 86 .auto-detected #detected-link { 87 color: #0000EE; 88 text-decoration: underline; 89 } 90 91 .lightbulb { 92 text-shadow: 0px 0px 1px black; 93 font-size: 1.4em; 94 vertical-align: middle; 95 line-height: 1; 96 user-select: none; 97 } 98 99 100 .section { 101 margin: 30px 0; 102 padding: 20px; 103 padding-top: 16px; 104 background-color: #fff; 105 border: 1px solid #ccc; 106 font-size: 1.1em; 107 } 108 109 .section:first-of-type { 110 margin-top: 3px; 111 padding-top: 4px; 112 padding-bottom: 6px; 113 } 114 115 #pwa-emoji { 116 display: none; 117 float: right; 118 margin: 15px; 119 margin-top: 40px; 120 font-size: 70px; 121 line-height: 1; 122 cursor: default; 123 user-select: none; 124 } 125 126 #pwa-infrared { 127 display: none; 128 float: right; 129 margin: 10px; 130 margin-top: 15px; 131 margin-right: 7px; 132 padding-left: 10px; 133 width: 100px; 134 image-rendering: pixelated; 135 cursor: default; 136 user-select: none; 137 } 138 139 .big-letter { 140 font-size: 1.25em; 141 font-variant: normal; 142 line-height: 0; 143 } 144 145 .section:last-of-type { 146 margin-bottom: 0; 147 padding-bottom: 10px; 148 } 149 150 ol { 151 padding-left: 25px; 152 } 153 154 li { 155 margin: 8px 0; 156 } 157 158 .toc li { 159 margin: 5px 0; 160 } 161 162 code { 163 background-color: #f0f0f0; 164 padding: 2px 4px; 165 font-family: "Courier New", monospace; 166 border: 1px solid #ddd; 167 } 168 169 .arrow { 170 display: inline-block; 171 width: 16px; 172 height: 10px; 173 position: relative; 174 margin: 0 6px; 175 vertical-align: middle; 176 } 177 178 .arrow::before { 179 content: ''; 180 position: absolute; 181 top: 50%; 182 left: 0; 183 width: 7.5px; 184 height: 2px; 185 background-color: #333; 186 transform: translateY(-50%); 187 } 188 189 .arrow::after { 190 content: ''; 191 position: absolute; 192 top: 50%; 193 left: 7.5px; 194 width: 0; 195 height: 0; 196 border-top: 5px solid transparent; 197 border-bottom: 5px solid transparent; 198 border-left: 6px solid #333; 199 transform: translateY(-50%); 200 } 201 202 .ui-element { 203 background-color: #f0f0f0; 204 padding: 2px 6px; 205 border-radius: 4px; 206 border: 1px solid #ddd; 207 font-size: 1em; 208 } 209 210 .dots { 211 display: inline-flex; 212 align-items: center; 213 gap: 3px; 214 height: 1em; 215 vertical-align: middle; 216 } 217 218 .dots::before, 219 .dots::after, 220 .dots span::before { 221 content: ''; 222 display: inline-block; 223 width: 3.5px; 224 height: 3.5px; 225 background-color: #333; 226 border-radius: 50%; 227 } 228 229 .dots span { 230 display: inline-flex; 231 } 232 233 .dots span::before { 234 content: ''; 235 } 236 237 .vdots { 238 display: inline-flex; 239 flex-direction: column; 240 align-items: center; 241 gap: 3px; 242 vertical-align: middle; 243 justify-content: center; 244 min-height: 1.8em; 245 box-sizing: content-box; 246 padding: 2px 0; 247 } 248 249 .vdots::before, 250 .vdots::after, 251 .vdots span::before { 252 content: ''; 253 display: block; 254 width: 3.5px; 255 height: 3.5px; 256 background-color: #333; 257 border-radius: 50%; 258 } 259 260 .vdots span { 261 display: flex; 262 } 263 264 .vdots span::before { 265 content: ''; 266 } 267 268 .ui-element:has(.vdots:only-child) { 269 padding-top: 6px; 270 padding-bottom: 6px; 271 } 272 273 .note { 274 font-style: italic; 275 color: #666; 276 border-left: 3px solid #ccc; 277 padding-left: 10px; 278 margin: 15px 0; 279 } 280 281 .note code { 282 font-style: normal; 283 } 284 285 .walkthrough-image { 286 max-width: 100%; 287 width: 500px; 288 display: block; 289 margin-left: auto; 290 margin-right: auto; 291 } 292 293 /* Dark mode styles */ 294 @media (prefers-color-scheme: dark) { 295 body { 296 background-color: #141414; 297 color: #ffffff; 298 } 299 300 h1, h2 { 301 color: #ffffff; 302 border-color: #666; 303 } 304 305 .toc, .section { 306 background-color: #1f1f22; 307 border: none; 308 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.7); 309 } 310 311 a.auto-detected, 312 a.auto-detected:visited { 313 background: linear-gradient(to top right, #1a1a3a 0%, #47496b 100%); 314 text-shadow: 0px 1px 1px rgb(0, 0, 0); 315 color: #ffffff; 316 } 317 318 .pwa-icon { 319 filter: drop-shadow(2px 2px 3px rgba(0, 0, 0, 0.5)); 320 } 321 322 a { 323 color: #80d4ff; 324 } 325 326 a:visited { 327 color: #80d4ff; 328 } 329 330 .auto-detected #detected-link { 331 color: #80d4ff; 332 } 333 334 .ui-element { 335 background-color: #3d3d3d; 336 border-color: #555; 337 color: #e0e0e0; 338 } 339 340 .arrow::before { 341 background-color: #fff; 342 } 343 344 .arrow::after { 345 border-left-color: #fff; 346 } 347 348 .dots::before, 349 .dots::after, 350 .dots span::before { 351 background-color: #e0e0e0; 352 } 353 354 .vdots::before, 355 .vdots::after, 356 .vdots span::before { 357 background-color: #e0e0e0; 358 } 359 360 .note { 361 color: #aaa; 362 border-left-color: #666; 363 } 364 365 footer { 366 border-top-color: #666; 367 color: #aaa; 368 } 369 } 370 371 /* Mobile responsive styles */ 372 @media (max-width: 768px) { 373 body { 374 padding: 0px; 375 } 376 377 h1 { 378 margin-top: 10px; 379 margin-bottom: 20px; 380 font-size: 1.8em; 381 } 382 383 .subtitle { 384 display: none; 385 } 386 387 .section, .toc { 388 margin: 20px 0; 389 padding: 15px 10px; 390 border-left: none; 391 border-right: none; 392 } 393 394 .section:first-of-type { 395 margin-top: 0px; 396 padding-top: .1px; 397 padding-bottom: 6px; 398 } 399 400 a.auto-detected { 401 margin: 20px 0; 402 padding: 12px 16px; 403 border: none; 404 border-radius: 0; 405 } 406 } 407 </style> 408 </head> 409 <body> 410 <div id="about-pwas" class="section"> 411 <span id="pwa-emoji" class="pwa-icon">📲</span> 412 <img id="pwa-infrared" src="infrared.png" alt=""> 413 <p><b><span class="big-letter">P</span>rogressive <span class="big-letter">W</span>eb <span class="big-letter">A</span>pps</b> (PWAs) are apps that can be installed directly from supported websites, independent of centralized app stores.</p> 414 415 <p>You can use the instructions below to install PWAs directly from your web browser.</p> 416 </div> 417 418 <a id="auto-detected" class="auto-detected" href="#"> 419 <p><span class="lightbulb">💡</span> Based on your system, you might want to jump directly to: <span id="detected-link"></span></p> 420 </a> 421 422 <div id="safari-ios" class="section"> 423 <h2>Safari (iOS / iPadOS)</h2> 424 <p class="note">Note: on iOS, Safari is the only browser that can install PWAs.</p> 425 <p>Open Safari and navigate to a website that supports PWA installation, then tap:</p> 426 <p>1. The three dots button in the bottom right corner of the screen:</p> 427 <img src="ios_safari/dots.jpeg" class="walkthrough-image"> 428 <p>2. Share:</p> 429 <img src="ios_safari/share.jpeg" class="walkthrough-image"> 430 <p>3. View More:</p> 431 <img src="ios_safari/view_more.jpeg" class="walkthrough-image"> 432 <p>4. Scroll down to reveal the hidden "Add to Home Screen" button:</p> 433 <video src="ios_safari/scroll_down.mov" autoplay muted loop playsinline class="walkthrough-image"></video> 434 <p>5. Tap the "Add to Home Screen" button:</p> 435 <img src="ios_safari/add_to_home_screen.jpeg" class="walkthrough-image"> 436 <p>6. Tap "Add":</p> 437 <img src="ios_safari/add.jpeg" class="walkthrough-image"> 438 <p>The app will be installed directly to your home screen.</p> 439 440 </div> 441 442 <div id="chrome-android" class="section"> 443 <h2>Chrome (Android)</h2> 444 <p>Navigate to a website that supports PWA installation, then tap:</p> 445 <p><span class="ui-element"><span class="vdots"><span></span></span></span> <span class="arrow"></span> Add to Home screen <span class="arrow"></span> Install.</p> 446 </div> 447 448 <div id="firefox-android" class="section"> 449 <h2>Firefox (Android)</h2> 450 <p>Navigate to a website that supports PWA installation, then tap:</p> 451 <p><span class="ui-element"><span class="vdots"><span></span></span></span> <span class="arrow"></span> <span class="ui-element"><span class="dots"><span></span></span> <span style="position: relative; top: 1px;">More</span></span> <span class="arrow"></span> Add to Home screen <span class="arrow"></span> Add to Home screen.</p> 452 </div> 453 454 <div id="safari-mac" class="section"> 455 <h2>Safari (macOS)</h2> 456 <p>Navigate to a website that supports PWA installation, then click File <span class="arrow"></span> Add to Dock.</p> 457 <p>The app will appear in your Dock and Applications folder, and will open in its own window without browser UI.</p> 458 <!-- <p class="note">Note: Requires macOS Sonoma 14+. Older versions may not support this feature.</p> --> 459 </div> 460 461 <div id="edge-windows" class="section"> 462 <h2>Microsoft Edge (Windows)</h2> 463 <p>Navigate to a website that supports PWA installation, then click:</p> 464 <p><span class="ui-element"><span class="dots"><span></span></span></span> <span class="arrow"></span> Apps <span class="arrow"></span> Install this site as an app.</p> 465 <p>The app will appear in the Start menu.</p> 466 </div> 467 468 <div id="chrome-desktop" class="section"> 469 <h2>Chrome (Desktop)</h2> 470 <p>Navigate to a website that supports PWA installation, click the install icon (downward pointing arrow) in the address bar, then click Install.</p> 471 <!-- <p class="note">Alternatively: <code>⋮</code> ➛ Cast, save, and share ➛ Install page as app</p> --> 472 <p>The app will appear in your applications folder or Start menu.</p> 473 </div> 474 475 <div id="firefox-windows" class="section"> 476 <h2>Firefox (Windows)</h2> 477 <p class="note">Note: Requires Firefox version 143 or later (150 or later if Firefox was installed from the Microsoft Store).</p> 478 <p>Navigate to a website that supports PWA installation, then click the <a href="https://support.mozilla.org/en-US/kb/web-apps-firefox-windows#w_install-web-apps" target="_blank">install button</a> in the address bar.</p> 479 <p>The app will appear in your taskbar and Start menu, and will open in its own window.</p> 480 </div> 481 482 <div id="firefox-desktop" class="section"> 483 <h2>Firefox (macOS / Linux)</h2> 484 <p><strong>⚠️ The macOS and Linux versions of Firefox do not support web app installation.</strong><br>Try <a href="#chrome-desktop">Chrome</a> or <a href="#safari-mac">Safari</a> instead.</p> 485 <p>Firefox for Windows added web app support in <a href="https://support.mozilla.org/en-US/kb/web-apps-firefox-windows" target="_blank">version 143</a> (September 2025), but support for macOS and Linux has not yet been announced.</p> 486 </div> 487 488 <div id="try-these-pwas" class="section"> 489 <h2>Progressive Web Apps You Can Install Right Now</h2> 490 491 <h3><a href="https://hunterirving.github.io/web_workshop/" target="_blank">Web Workshop</a></h3> 492 <p class="note">Craft handmade websites in their natural habitat with this in-browser HTML editor. Works great on desktop or mobile.</p> 493 494 <h3><a href="https://hunterirving.com">HunterIrving.com</a></h3> 495 <p class="note">Experience Huntergram, Gobbler, and more in the dedicated hunterirving.com PWA.</p> 496 497 <h3><a href="https://hunterirving.github.io/qr/">QR</a></h3> 498 <p class="note">A no-nonsense QR code generator. Great for sharing links to PWAs you've developed with nearby friends.</p> 499 500 <h3><a href="https://github.com/hunterirving/mixapps">Mixapps</a></h3> 501 <p class="note">Mixapps are like mixtapes or mix CDs, but packaged as PWAs that you can install for offline use. Use <a href="https://github.com/hunterirving/mixapps">this link</a> to learn how to create your own mixapps, or <a href="https://hunterirving.com/worn_grooves/">click here</a> to install one assembled from public domain recordings.</p> 502 503 <h3><a href="https://hunterirving.github.io/almanac">Almanac</a></h3> 504 <p class="note">A companion app for the first Animal Crossing game that lets you add in-game events to your device's calendar.</p> 505 506 <!-- <h3><a href="https://hunterirving.github.io/klaxon/" target="_blank">Klaxon</a></h3> 507 <p class="note">A chess clock in your pocket, optimized for touchscreen devices and competitive play.</p> 508 509 <h3><a href="https://hunterirving.github.io/hourglass/">Hourglass</a></h3> 510 <p class="note">Speedrun your life with this simple, focused time tracking tool.</p> 511 512 <h3><a href="https://hunterirving.github.io/pop_viz/">Pop Viz</a></h3> 513 <p class="note">What does 100,000 people look like? Don't ask me — install this Progressive Web App.</p> --> 514 515 <!-- <h3><a href="https://hunterirving.github.io/web_workshop/pages/snake/">SNAKE</a></h3> 516 <p class="note">The classic game, reimagined for the modern era.</p> --> 517 </div> 518 519 <script> 520 function detectPlatform() { 521 const userAgent = navigator.userAgent.toLowerCase(); 522 const platform = navigator.platform.toLowerCase(); 523 524 let detectedOS = ''; 525 let detectedBrowser = ''; 526 let targetSection = ''; 527 528 // Detect OS 529 if (userAgent.includes('android')) { 530 detectedOS = 'Android'; 531 } else if (userAgent.includes('iphone') || userAgent.includes('ipad')) { 532 detectedOS = 'iOS'; 533 } else if (platform.includes('win')) { 534 detectedOS = 'Windows'; 535 } else if (platform.includes('mac')) { 536 detectedOS = 'macOS'; 537 } else if (platform.includes('linux')) { 538 detectedOS = 'Linux'; 539 } 540 541 // Detect Browser - iOS only allows PWA installation through Safari 542 if (detectedOS === 'iOS') { 543 // On iOS, all browsers use Safari's WebKit engine 544 // Only Safari can install PWAs, so always direct to Safari section 545 detectedBrowser = 'Safari'; 546 targetSection = 'safari-ios'; 547 } else if (userAgent.includes('firefox')) { 548 detectedBrowser = 'Firefox'; 549 if (detectedOS === 'Android') { 550 targetSection = 'firefox-android'; 551 } else if (detectedOS === 'Windows') { 552 targetSection = 'firefox-windows'; 553 } else { 554 targetSection = 'firefox-desktop'; 555 } 556 } else if (userAgent.includes('safari') && !userAgent.includes('chrome')) { 557 detectedBrowser = 'Safari'; 558 targetSection = 'safari-mac'; 559 } else if (userAgent.includes('edg')) { 560 detectedBrowser = 'Edge'; 561 targetSection = 'edge-windows'; 562 } else if (userAgent.includes('chrome')) { 563 detectedBrowser = 'Chrome'; 564 if (detectedOS === 'Android') { 565 targetSection = 'chrome-android'; 566 } else { 567 targetSection = 'chrome-desktop'; 568 } 569 } 570 571 const isPhone = (detectedOS === 'Android' || detectedOS === 'iOS'); 572 if (isPhone) { 573 document.getElementById('pwa-emoji').style.display = 'inline'; 574 } else { 575 document.getElementById('pwa-infrared').style.display = 'block'; 576 } 577 578 if (targetSection) { 579 const autoDetectedDiv = document.getElementById('auto-detected'); 580 const detectedLink = document.getElementById('detected-link'); 581 582 autoDetectedDiv.href = `#${targetSection}`; 583 detectedLink.textContent = `${detectedBrowser} on ${detectedOS}`; 584 autoDetectedDiv.style.display = 'block'; 585 } 586 } 587 588 // Run detection when page loads 589 window.addEventListener('load', detectPlatform); 590 </script> 591 </body> 592 </html>