Skip to content

feat(pwa): Add icons and a scan shortcut to the PWA app shortcuts#128

Merged
OffCrazyFreak merged 1 commit into
devfrom
feat/pwa-shortcut-icons
Jul 25, 2026
Merged

feat(pwa): Add icons and a scan shortcut to the PWA app shortcuts#128
OffCrazyFreak merged 1 commit into
devfrom
feat/pwa-shortcut-icons

Conversation

@OffCrazyFreak

Copy link
Copy Markdown
Owner

The PWA app shortcuts had no icons member at all, so long-pressing the installed icon showed bare labels. This adds artwork, a Skeniraj shortcut, and fixes a launch_handler value that was quietly breaking every shortcut.

Icons

manifest.ts built shortcuts from userNavItems but only ever emitted name, short_name and url.

Chrome accepts PNG only for shortcut icons, so the brand SVGs cannot be linked. New generator frontend/scripts/generate-shortcut-icons.mjs follows the same one-off pattern as generate-pwa-icons.mjs and needs no new dependency: sharp was already a devDependency, react-dom and lucide-react already dependencies.

It renders the same lucide-react component the nav uses through renderToStaticMarkup, then rasterizes with sharp. Rendering the component rather than copying a path is what stops a shortcut icon from drifting away from its nav icon.

Output is 192x192, brand green on a rounded white tile, glyph at 52% so a launcher's circular mask cannot clip it. The rounding is for desktop, where Chrome and Edge draw jump-list icons unmasked and a hard square would read as a blank block.

manifest.ts derives each src from the nav item's id, so dropping a comingSoon flag wires a shortcut up by itself. Each shortcut also gains a description, which browsers hand to assistive tech and which was missing entirely.

The Skeniraj shortcut

The scanner is imperative (context/scanner-context.tsx) and has no route, so the shortcut points at /?scan=1. A new components/custom/pwa/scan-shortcut.tsx reads the flag through the existing useClientSearchParams, strips it with replaceState before opening the camera (so a refresh or a back navigation does not reopen it), and routes the scanned code through the existing useProductNavigation.

Deliberately not ?modal=scan: the ?modal= params are durable, shareable modal state, which is wrong for a camera. This is a one-shot launch intent.

It is first in the array. Chrome for Android shows 3 shortcuts (it allowed 4 until Chrome 92 started injecting its own "Site settings" entry, which takes a slot), and scanning is the fastest path from launcher to a price. Desktop shows up to 10.

Order Shortcut Url Icon
1 Skeniraj /?scan=1 ScanBarcode
2 Popisi /shopping-lists ListChecks
3 Praćenje /watchlist Eye

Bug found on the way: launch_handler

launch_handler was { client_mode: "focus-existing" }. Per the spec, that focuses an already-open window without navigating, and hands the target url to window.launchQueue for the app to handle. Nothing in this codebase consumes launchQueue.

So launching any shortcut while the PWA was already open did nothing at all. That silently affected Popisi and Praćenje, and very likely /share-target too.

Changed to navigate-existing, which still reuses the open window (the original comment's stated intent) but actually navigates to the url. Happy to split this out if it should not ride along.

Also here

  • The scanner's camera reset button now uses the modal footer's icon/iconPlacement form. Kept icon-only at every width with its tooltip, per review feedback.
  • docs/PWA.md gains an App shortcuts section (slot math, the icon pipeline, why Skeniraj needs a url flag), a corrected launch_handler row, key-file entries, and two gotchas: the focus-existing trap above, and the fact that Android caches the WebAPK so manifest changes need a reinstall.
  • docs/BRAND.md notes that shortcut icons are the deliberate exception to "everything derives from the cart".
  • TODO(#127) on the digital-cards and map nav entries.

Follow-up

#127 tracks adding Karta and Digitalne kartice once they ship. It is really a "pick the final three" decision rather than an append, since six candidates will eventually compete for three Android slots. It also records the trap that Kartice will appear by itself when its flag drops, pointing at a PNG that does not exist yet.

Verification

Check Result
tsc --noEmit clean
eslint src 0 errors, 20 pre-existing warnings, none in new files
prettier --check clean across src, scripts, docs
Generated PNGs 3 files, all 192x192, inspected visually

Also confirmed directly that Slottable with undefined children renders on React 19.2.8, since a self-closing <Button icon=... /> is a new shape for this repo.

Not verified: the runtime scan flow, since the dev server is not mine to run. Worth a click-through of /?scan=1, and a reinstall on a phone to see the icons.

Changes:
- Add scripts/generate-shortcut-icons.mjs, rendering the nav's own lucide
  components to 192x192 PNGs on a rounded white tile
- Give every manifest shortcut an icon and an accessible description
- Add a "Skeniraj" shortcut at /?scan=1, served by a new ScanShortcut
  component that opens the scanner modal and routes the code to its product
- Switch launch_handler to navigate-existing, since focus-existing only
  focused the window and left the url to an unconsumed launchQueue
- Match the scanner's camera reset button to the modal footer's, icon-only
- Document app shortcuts in PWA.md and their icons in BRAND.md
- Flag the Karta and Digitalne kartice follow-up with TODO(#127)

The shortcuts had no artwork at all, so the long-press menu showed bare
labels next to Chrome's own Site settings entry.

Notes:
- Chrome accepts PNG only for shortcut icons, hence the generator rather
  than reusing the brand SVGs.
- Android shows 3 shortcuts (Chrome 92 took a fourth slot for Site
  settings), so array order decides what a phone surfaces. See #127.
- Android caches the WebAPK; reinstall the PWA to see the new icons.
@netlify

netlify Bot commented Jul 25, 2026

Copy link
Copy Markdown

Deploy Preview for disscount failed. Why did it fail? →

Name Link
🔨 Latest commit 95f6345
🔍 Latest deploy log https://app.netlify.com/projects/disscount/deploys/6a64b4dc3628de00083c023c

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@OffCrazyFreak, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4680ce30-959c-4895-a667-05644700f706

📥 Commits

Reviewing files that changed from the base of the PR and between 0fd57bc and 95f6345.

⛔ Files ignored due to path filters (3)
  • frontend/public/brand/shortcuts/scan.png is excluded by !**/*.png
  • frontend/public/brand/shortcuts/shopping-lists.png is excluded by !**/*.png
  • frontend/public/brand/shortcuts/watchlist.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • docs/BRAND.md
  • docs/PWA.md
  • frontend/scripts/generate-shortcut-icons.mjs
  • frontend/src/app/manifest.ts
  • frontend/src/app/providers/providers.tsx
  • frontend/src/components/custom/pwa/scan-shortcut.tsx
  • frontend/src/components/scanner/camera-select.tsx
  • frontend/src/constants/navigation.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@OffCrazyFreak
OffCrazyFreak merged commit e7fcd2a into dev Jul 25, 2026
3 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant