feat: make the app installable as a desktop app - #464
Merged
Merged
Conversation
Chrome and Edge can now install the app: the manifest gains PNG icons (192, 512 and a maskable 512) exported from new brand art, a stable `id`, and a `focus-existing` launch handler so a second launch reuses the open window instead of fighting it for the radio. The favicon is now a 16/32/48 ICO. The title bar follows the active theme, while the static `theme-color` keeps the accent for link-preview crawlers. The app offers installation itself from the connect screen, Settings → Display and the command palette. It keeps Chromium's install prompt (captured before hydration, which it can beat) and falls back to an install guide for Firefox, Safari and a dismissed prompt. Every entry point disappears once the app is installed. The README documents installing, updating and uninstalling. Closes #446 Closes #447 Closes #448 Closes #449
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR delivers the whole desktop-install epic (#446 to #449) in one PR, as requested.
#446: make the app installable
Icons.
public/icon-192.png,icon-512.pngand a maskableicon-maskable-512.png.app/favicon.icois now a 16/32/48 ICO. The export command is documented inpublic/brand/README.md, and it reproduces the committed files byte for byte.app-icon.svgas specified. The standard icons and the favicon come from a newpublic/brand/app-tile.svgmaster instead: the same mark and background on a rounded tile, with the mark near full size. The OS shows standard icons uncropped, so a straight export of the full-bleedapp-icon.svgwould be a hard square with the mark at about 56% width. At taskbar and tab sizes that shrinks the mark to a few pixels.Manifest. Adds
"id": "/"and"launch_handler": { "client_mode": "focus-existing" }, plus the three icons; the.icoentry is gone.background_colorandtheme_colornow match the real dark--bgand--surface; the old#0a0e14matched neither. The name is unchanged: it was already "MeshCore Desktop" from chore: rename the app and repository from MeshCore-WebAgent to MeshCore-Desktop #452.Title bar (departure from the ticket). Instead of per-scheme
<meta name="theme-color" media=…>entries, the statictheme-colorstays the brand accent. The pre-paint theme script andThemeProviderthen repaint it to the header's--surfacefor the active theme. Two reasons:media.prefers-color-schemequery can't follow the in-app theme toggle.React re-adds its own copy of that meta at hydration, so
ThemeProviderrepaints everytheme-colormeta, not just the first.#447: install entry points
lib/pwa/install.tscapturesbeforeinstallprompt(callingpreventDefault()) and clears it onappinstalledor onceprompt()settles. The store gets runtime-onlyinstallPrompt,appInstalledandinstallGuideOpen. They are not preferences, so they are not in the preferences blob.reset()preservesinstallPromptandappInstalled. It closes the guide, because it also zeroes the modal count under it.display-mode: standalone, including a change event for a tab Chrome moves into the app window without reloading.appinstalled, in the tab that installs it.related_applicationsentry in the manifest, read withnavigator.getInstalledRelatedApps(). This lets any later tab or reload know too, so the entry points don't come back after installing.beforeinstallpromptbefore hydration reaches the module that listens for it. I measured it: fired at 223 ms, after theloadevent, and the prompt was lost for that page load. A small inline<head>script now parks an early event onwindow, and the module adopts it when it loads. The name of thatwindowproperty is inlib/pwa/config.ts, so the server layout never imports the store.prompt()when a prompt was captured, and opens the feat(ui): in-app guide for installing the desktop app #448 guide otherwise:opensDialog, because it can open the guide.#448: install guide
InstallGuideModal, built onModalShelland keeping no state of its own, covers what you get, the steps for the detected browser, and how to uninstall.#449: docs
feat:, so the squash commit lands inCHANGELOG.mdand the release notes as "make the app installable as a desktop app". The notes still need a check once that release is cut (the second half of docs: document and announce the installable desktop app #449).Screenshots
Verification
Tested in Chrome on Windows against the burner radio (KN0.APP, Heltec V4.3, over USB), in
next devand in the production export served fromout/on localhost:image/png. Chrome firesbeforeinstallprompt, which is Chromium's signal that the installability criteria are met, and the app captures it.out/index.htmlhas a single accenttheme-colormeta.reset(). With the radio connected, Settings → Display shows Learn more and Install.beforeinstallpromptswallowed. The connect row opens the guide with the "use Chrome or Edge" steps, with no Install now, and nothing is logged to the console.appinstalledremoves the entry points from the tab. A fresh load wheregetInstalledRelatedApps()is stubbed to report the app shows none. With the real API, the lookup returns[]without error, and the prompt still fires withrelated_applicationsin the manifest.theme-colormeta follows the theme toggle,#1a1d27dark and#f4f6f9light, in both dev and the production export.Still needs a human: I didn't click Install in this Chrome profile, because it would install an app on the machine. Please confirm:
getInstalledRelatedApps()matching the relativerelated_applicationsURL, which I couldn't check without installing.The Chrome and Edge menu wording and the es/de/fr strings are drafts for human review.
Issues
Type of Change
!-- Breaking change (fix or feature that would cause existingfunctionality to change)
feat-- New feature (non-breaking change which adds functionality)fix-- Bug fix (non-breaking change which fixes an issue)docs-- Additional or updated documentationstyle-- Code style changes (formatting, missing semi colons, etc)refactor-- Code refactorperf-- Performance improvementtest-- Tests (adding or updating tests)build-- Build system or external dependencies changesci-- Build configuration changechore-- Grunt tasksrevert-- Revert previous changes